summaryrefslogtreecommitdiff
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/88pm860x-ts.c20
-rw-r--r--drivers/input/touchscreen/Kconfig173
-rw-r--r--drivers/input/touchscreen/Makefile17
-rw-r--r--drivers/input/touchscreen/ad7877.c22
-rw-r--r--drivers/input/touchscreen/ad7879-i2c.c13
-rw-r--r--drivers/input/touchscreen/ad7879-spi.c7
-rw-r--r--drivers/input/touchscreen/ad7879.c24
-rw-r--r--drivers/input/touchscreen/ad7879.h3
-rw-r--r--drivers/input/touchscreen/ads7846.c227
-rw-r--r--drivers/input/touchscreen/apple_z2.c477
-rw-r--r--drivers/input/touchscreen/ar1021_i2c.c15
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c161
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c16
-rw-r--r--drivers/input/touchscreen/bcm_iproc_tsc.c4
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c84
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c68
-rw-r--r--drivers/input/touchscreen/chipone_icn8318.c16
-rw-r--r--drivers/input/touchscreen/chipone_icn8505.c13
-rw-r--r--drivers/input/touchscreen/colibri-vf50-ts.c10
-rw-r--r--drivers/input/touchscreen/cy8ctma140.c23
-rw-r--r--drivers/input/touchscreen/cy8ctmg110_ts.c11
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c2180
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.h448
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c72
-rw-r--r--drivers/input/touchscreen/cyttsp4_spi.c187
-rw-r--r--drivers/input/touchscreen/cyttsp5.c119
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c47
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h5
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c61
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c_common.c85
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c2
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c6
-rw-r--r--drivers/input/touchscreen/dynapro.c2
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c599
-rw-r--r--drivers/input/touchscreen/eeti_ts.c14
-rw-r--r--drivers/input/touchscreen/egalax_ts.c16
-rw-r--r--drivers/input/touchscreen/egalax_ts_serial.c2
-rw-r--r--drivers/input/touchscreen/ektf2127.c56
-rw-r--r--drivers/input/touchscreen/elants_i2c.c51
-rw-r--r--drivers/input/touchscreen/elo.c10
-rw-r--r--drivers/input/touchscreen/exc3000.c54
-rw-r--r--drivers/input/touchscreen/fsl-imx25-tcq.c3
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c2
-rw-r--r--drivers/input/touchscreen/goodix.c169
-rw-r--r--drivers/input/touchscreen/goodix.h1
-rw-r--r--drivers/input/touchscreen/goodix_berlin.h39
-rw-r--r--drivers/input/touchscreen/goodix_berlin_core.c802
-rw-r--r--drivers/input/touchscreen/goodix_berlin_i2c.c84
-rw-r--r--drivers/input/touchscreen/goodix_berlin_spi.c203
-rw-r--r--drivers/input/touchscreen/gunze.c2
-rw-r--r--drivers/input/touchscreen/hampshire.c2
-rw-r--r--drivers/input/touchscreen/hideep.c66
-rw-r--r--drivers/input/touchscreen/himax_hx83112b.c127
-rw-r--r--drivers/input/touchscreen/himax_hx852x.c503
-rw-r--r--drivers/input/touchscreen/hycon-hy46xx.c16
-rw-r--r--drivers/input/touchscreen/hynitron-cst816x.c253
-rw-r--r--drivers/input/touchscreen/hynitron_cstxxx.c6
-rw-r--r--drivers/input/touchscreen/ili210x.c190
-rw-r--r--drivers/input/touchscreen/ilitek_ts_i2c.c63
-rw-r--r--drivers/input/touchscreen/imagis.c156
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c131
-rw-r--r--drivers/input/touchscreen/inexio.c2
-rw-r--r--drivers/input/touchscreen/ipaq-micro-ts.c11
-rw-r--r--drivers/input/touchscreen/iqs5xx.c36
-rw-r--r--drivers/input/touchscreen/iqs7211.c2557
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c98
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c14
-rw-r--r--drivers/input/touchscreen/max11801_ts.c4
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c8
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c287
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c75
-rw-r--r--drivers/input/touchscreen/migor_ts.c12
-rw-r--r--drivers/input/touchscreen/mms114.c101
-rw-r--r--drivers/input/touchscreen/msg2638.c10
-rw-r--r--drivers/input/touchscreen/mtouch.c2
-rw-r--r--drivers/input/touchscreen/novatek-nvt-ts.c354
-rw-r--r--drivers/input/touchscreen/pcap_ts.c4
-rw-r--r--drivers/input/touchscreen/penmount.c2
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c56
-rw-r--r--drivers/input/touchscreen/raspberrypi-ts.c7
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c66
-rw-r--r--drivers/input/touchscreen/resistive-adc-touch.c8
-rw-r--r--drivers/input/touchscreen/rohm_bu21023.c115
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c464
-rw-r--r--drivers/input/touchscreen/s6sy761.c33
-rw-r--r--drivers/input/touchscreen/silead.c51
-rw-r--r--drivers/input/touchscreen/sis_i2c.c28
-rw-r--r--drivers/input/touchscreen/st1232.c47
-rw-r--r--drivers/input/touchscreen/stmfts.c30
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c15
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c12
-rw-r--r--drivers/input/touchscreen/sur40.c13
-rw-r--r--drivers/input/touchscreen/surface3_spi.c27
-rw-r--r--drivers/input/touchscreen/sx8654.c16
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c15
-rw-r--r--drivers/input/touchscreen/touchit213.c2
-rw-r--r--drivers/input/touchscreen/touchright.c2
-rw-r--r--drivers/input/touchscreen/touchwin.c2
-rw-r--r--drivers/input/touchscreen/ts4800-ts.c5
-rw-r--r--drivers/input/touchscreen/tsc2004.c17
-rw-r--r--drivers/input/touchscreen/tsc2005.c13
-rw-r--r--drivers/input/touchscreen/tsc2007.h2
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c63
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c275
-rw-r--r--drivers/input/touchscreen/tsc200x-core.h2
-rw-r--r--drivers/input/touchscreen/tsc40.c2
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c458
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c971
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c16
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c37
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c36
-rw-r--r--drivers/input/touchscreen/wm831x-ts.c4
-rw-r--r--drivers/input/touchscreen/wm9705.c1
-rw-r--r--drivers/input/touchscreen/wm9712.c1
-rw-r--r--drivers/input/touchscreen/wm9713.c1
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c19
-rw-r--r--drivers/input/touchscreen/zet6223.c8
-rw-r--r--drivers/input/touchscreen/zforce_ts.c502
-rw-r--r--drivers/input/touchscreen/zinitix.c156
-rw-r--r--drivers/input/touchscreen/zylonite-wm97xx.c220
120 files changed, 8379 insertions, 7254 deletions
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 81a3ea4b9a3d..0468ce2b216f 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -117,13 +117,14 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
struct pm860x_chip *chip,
int *res_x)
{
- struct device_node *np = pdev->dev.parent->of_node;
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
: chip->companion;
int data, n, ret;
- if (!np)
+ if (!pdev->dev.parent->of_node)
return -ENODEV;
- np = of_get_child_by_name(np, "touch");
+
+ struct device_node *np __free(device_node) =
+ of_get_child_by_name(pdev->dev.parent->of_node, "touch");
if (!np) {
dev_err(&pdev->dev, "Can't find touch node\n");
return -EINVAL;
@@ -141,13 +142,13 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
if (data) {
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
/* set tsi prebias time */
if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
/* set prebias & prechg time of pen detect */
data = 0;
@@ -158,18 +159,11 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
if (data) {
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
- of_node_put(np);
-
return 0;
-
-err_put_node:
- of_node_put(np);
-
- return -EINVAL;
}
#else
#define pm860x_touch_dt_init(x, y, z) (-1)
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 68d99a112e14..7d5b72ee07fa 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -103,6 +103,18 @@ config TOUCHSCREEN_ADC
To compile this driver as a module, choose M here: the
module will be called resistive-adc-touch.ko.
+config TOUCHSCREEN_APPLE_Z2
+ tristate "Apple Z2 touchscreens"
+ depends on SPI && (ARCH_APPLE || COMPILE_TEST)
+ help
+ Say Y here if you have an ARM Apple device with
+ a touchscreen or a touchbar.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apple_z2.
+
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
@@ -254,36 +266,6 @@ config TOUCHSCREEN_CYTTSP_SPI
To compile this driver as a module, choose M here: the
module will be called cyttsp_spi.
-config TOUCHSCREEN_CYTTSP4_CORE
- tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
- help
- Core driver for Cypress TrueTouch(tm) Standard Product
- Generation4 touchscreen controllers.
-
- Say Y here if you have a Cypress Gen4 touchscreen.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here.
-
-config TOUCHSCREEN_CYTTSP4_I2C
- tristate "support I2C bus connection"
- depends on TOUCHSCREEN_CYTTSP4_CORE && I2C
- help
- Say Y here if the touchscreen is connected via I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called cyttsp4_i2c.
-
-config TOUCHSCREEN_CYTTSP4_SPI
- tristate "support SPI bus connection"
- depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER
- help
- Say Y here if the touchscreen is connected via SPI bus.
-
- To compile this driver as a module, choose M here: the
- module will be called cyttsp4_spi.
-
config TOUCHSCREEN_CYTTSP5
tristate "Cypress TrueTouch Gen5 Touchscreen Driver"
depends on I2C
@@ -416,9 +398,41 @@ config TOUCHSCREEN_GOODIX
To compile this driver as a module, choose M here: the
module will be called goodix.
+config TOUCHSCREEN_GOODIX_BERLIN_CORE
+ tristate
+
+config TOUCHSCREEN_GOODIX_BERLIN_I2C
+ tristate "Goodix Berlin I2C touchscreen"
+ depends on I2C
+ select REGMAP_I2C
+ select TOUCHSCREEN_GOODIX_BERLIN_CORE
+ help
+ Say Y here if you have a Goodix Berlin IC connected to
+ your system via I2C.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called goodix_berlin_i2c.
+
+config TOUCHSCREEN_GOODIX_BERLIN_SPI
+ tristate "Goodix Berlin SPI touchscreen"
+ depends on SPI_MASTER
+ select REGMAP
+ select TOUCHSCREEN_GOODIX_BERLIN_CORE
+ help
+ Say Y here if you have a Goodix Berlin IC connected to
+ your system via SPI.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called goodix_berlin_spi.
+
config TOUCHSCREEN_HIDEEP
tristate "HiDeep Touch IC"
depends on I2C
+ select REGMAP_I2C
help
Say Y here if you have a touchscreen using HiDeep.
@@ -427,9 +441,20 @@ config TOUCHSCREEN_HIDEEP
To compile this driver as a module, choose M here : the
module will be called hideep_ts.
+config TOUCHSCREEN_HIMAX_HX852X
+ tristate "Himax HX852x(ES) touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a Himax HX852x(ES) touchscreen.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called himax_hx852x.
+
config TOUCHSCREEN_HYCON_HY46XX
tristate "Hycon hy46xx touchscreen support"
depends on I2C
+ select REGMAP_I2C
help
Say Y here if you have a touchscreen using Hycon hy46xx
@@ -450,6 +475,18 @@ config TOUCHSCREEN_HYNITRON_CSTXXX
To compile this driver as a module, choose M here: the
module will be called hynitron-cstxxx.
+config TOUCHSCREEN_HYNITRON_CST816X
+ tristate "Hynitron CST816x touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a touchscreen using a Hynitron
+ CST816x series touchscreen controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hynitron-cst816x.
+
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
@@ -490,18 +527,6 @@ config TOUCHSCREEN_IPROC
To compile this driver as a module, choose M here: the
module will be called bcm_iproc_tsc.
-config TOUCHSCREEN_S3C2410
- tristate "Samsung S3C2410/generic touchscreen input driver"
- depends on ARCH_S3C24XX || SAMSUNG_DEV_TS
- depends on S3C_ADC
- help
- Say Y here if you have the s3c2410 touchscreen.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called s3c2410_ts.
-
config TOUCHSCREEN_S6SY761
tristate "Samsung S6SY761 Touchscreen driver"
depends on I2C
@@ -607,18 +632,6 @@ config TOUCHSCREEN_MAX11801
To compile this driver as a module, choose M here: the
module will be called max11801_ts.
-config TOUCHSCREEN_MCS5000
- tristate "MELFAS MCS-5000 touchscreen"
- depends on I2C
- help
- Say Y here if you have the MELFAS MCS-5000 touchscreen controller
- chip in your system.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called mcs5000_ts.
-
config TOUCHSCREEN_MMS114
tristate "MELFAS MMS114 touchscreen"
depends on I2C
@@ -666,6 +679,16 @@ config TOUCHSCREEN_MTOUCH
To compile this driver as a module, choose M here: the
module will be called mtouch.
+config TOUCHSCREEN_NOVATEK_NVT_TS
+ tristate "Novatek NT11205 touchscreen support"
+ depends on I2C
+ help
+ Say Y here if you have a Novatek NT11205 touchscreen.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called novatek-nvt-ts.
+
config TOUCHSCREEN_IMAGIS
tristate "Imagis touchscreen support"
depends on I2C
@@ -702,6 +725,7 @@ config TOUCHSCREEN_INEXIO
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
+ depends on ISA
help
Say Y here if you have the ICS MicroClock MK712 touchscreen
controller chip in your system.
@@ -770,6 +794,7 @@ config TOUCHSCREEN_PENMOUNT
config TOUCHSCREEN_EDT_FT5X06
tristate "EDT FocalTech FT5x06 I2C Touchscreen support"
depends on I2C
+ select REGMAP_I2C
help
Say Y here if you have an EDT "Polytouch" touchscreen based
on the FocalTech FT5x06 family of controllers connected to
@@ -839,22 +864,6 @@ config TOUCHSCREEN_TI_AM335X_TSC
To compile this driver as a module, choose M here: the
module will be called ti_am335x_tsc.
-config TOUCHSCREEN_UCB1400
- tristate "Philips UCB1400 touchscreen"
- depends on AC97_BUS
- depends on UCB1400_CORE
- help
- This enables support for the Philips UCB1400 touchscreen interface.
- The UCB1400 is an AC97 audio codec. The touchscreen interface
- will be initialized only after the ALSA subsystem has been
- brought up and the UCB1400 detected. You therefore have to
- configure ALSA support as well (either built-in or modular,
- independently of whether this driver is itself built-in or
- modular) for this driver to work.
-
- To compile this driver as a module, choose M here: the
- module will be called ucb1400_ts.
-
config TOUCHSCREEN_PIXCIR
tristate "PIXCIR I2C touchscreens"
depends on I2C
@@ -940,20 +949,6 @@ config TOUCHSCREEN_WM97XX_MAINSTONE
To compile this driver as a module, choose M here: the
module will be called mainstone-wm97xx.
-config TOUCHSCREEN_WM97XX_ZYLONITE
- tristate "Zylonite accelerated touch"
- depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE
- depends on SND_PXA2XX_LIB_AC97
- select TOUCHSCREEN_WM9713
- help
- Say Y here for support for streaming mode with the touchscreen
- on Zylonite systems.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called zylonite-wm97xx.
-
config TOUCHSCREEN_USB_COMPOSITE
tristate "USB Touchscreen Driver"
depends on USB_ARCH_HAS_HCD
@@ -1395,6 +1390,16 @@ config TOUCHSCREEN_IQS5XX
To compile this driver as a module, choose M here: the
module will be called iqs5xx.
+config TOUCHSCREEN_IQS7211
+ tristate "Azoteq IQS7210A/7211A/E trackpad/touchscreen controller"
+ depends on I2C
+ help
+ Say Y to enable support for the Azoteq IQS7210A/7211A/E
+ family of trackpad/touchscreen controllers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iqs7211.
+
config TOUCHSCREEN_ZINITIX
tristate "Zinitix touchscreen support"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 4968c370479a..ab9abd151078 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
@@ -25,11 +26,8 @@ obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMA140) += cy8ctma140.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP5) += cyttsp5.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
@@ -47,8 +45,13 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o
+obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o
+obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o
obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o
+obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CST816X) += hynitron-cst816x.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o
obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o
@@ -60,13 +63,13 @@ obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o
obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
-obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o
obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
+obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o
@@ -76,7 +79,6 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o
-obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_S6SY761) += s6sy761.o
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
@@ -98,7 +100,6 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
tsc2007-y := tsc2007_core.o
tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
-obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o
@@ -108,7 +109,6 @@ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
-obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o
@@ -117,5 +117,6 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
+obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o
obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o
obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index 08f5372f0bfd..c9aa1847265a 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -375,7 +375,7 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
static void ad7877_timer(struct timer_list *t)
{
- struct ad7877 *ts = from_timer(ts, t, timer);
+ struct ad7877 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -415,7 +415,7 @@ static void ad7877_disable(void *data)
ts->disabled = true;
disable_irq(ts->spi->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
@@ -612,10 +612,11 @@ static umode_t ad7877_attr_is_visible(struct kobject *kobj,
return mode;
}
-static const struct attribute_group ad7877_attr_group = {
+static const struct attribute_group ad7877_group = {
.is_visible = ad7877_attr_is_visible,
.attrs = ad7877_attributes,
};
+__ATTRIBUTE_GROUPS(ad7877);
static void ad7877_setup_ts_def_msg(struct spi_device *spi, struct ad7877 *ts)
{
@@ -777,10 +778,6 @@ static int ad7877_probe(struct spi_device *spi)
return err;
}
- err = devm_device_add_group(&spi->dev, &ad7877_attr_group);
- if (err)
- return err;
-
err = input_register_device(input_dev);
if (err)
return err;
@@ -788,7 +785,7 @@ static int ad7877_probe(struct spi_device *spi)
return 0;
}
-static int __maybe_unused ad7877_suspend(struct device *dev)
+static int ad7877_suspend(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
@@ -797,7 +794,7 @@ static int __maybe_unused ad7877_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ad7877_resume(struct device *dev)
+static int ad7877_resume(struct device *dev)
{
struct ad7877 *ts = dev_get_drvdata(dev);
@@ -806,12 +803,13 @@ static int __maybe_unused ad7877_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ad7877_pm, ad7877_suspend, ad7877_resume);
static struct spi_driver ad7877_driver = {
.driver = {
- .name = "ad7877",
- .pm = &ad7877_pm,
+ .name = "ad7877",
+ .dev_groups = ad7877_groups,
+ .pm = pm_sleep_ptr(&ad7877_pm),
},
.probe = ad7877_probe,
};
diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c
index dd8f31737bb8..e5b99312c3d9 100644
--- a/drivers/input/touchscreen/ad7879-i2c.c
+++ b/drivers/input/touchscreen/ad7879-i2c.c
@@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ad7879_id[] = {
- { "ad7879", 0 },
- { "ad7889", 0 },
+ { "ad7879" },
+ { "ad7889" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad7879_id);
@@ -58,11 +58,12 @@ MODULE_DEVICE_TABLE(of, ad7879_i2c_dt_ids);
static struct i2c_driver ad7879_i2c_driver = {
.driver = {
- .name = "ad7879",
- .pm = &ad7879_pm_ops,
- .of_match_table = of_match_ptr(ad7879_i2c_dt_ids),
+ .name = "ad7879",
+ .dev_groups = ad7879_groups,
+ .pm = &ad7879_pm_ops,
+ .of_match_table = of_match_ptr(ad7879_i2c_dt_ids),
},
- .probe_new = ad7879_i2c_probe,
+ .probe = ad7879_i2c_probe,
.id_table = ad7879_id,
};
diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c
index 50e889846800..064968fe57cf 100644
--- a/drivers/input/touchscreen/ad7879-spi.c
+++ b/drivers/input/touchscreen/ad7879-spi.c
@@ -56,9 +56,10 @@ MODULE_DEVICE_TABLE(of, ad7879_spi_dt_ids);
static struct spi_driver ad7879_spi_driver = {
.driver = {
- .name = "ad7879",
- .pm = &ad7879_pm_ops,
- .of_match_table = of_match_ptr(ad7879_spi_dt_ids),
+ .name = "ad7879",
+ .dev_groups = ad7879_groups,
+ .pm = &ad7879_pm_ops,
+ .of_match_table = of_match_ptr(ad7879_spi_dt_ids),
},
.probe = ad7879_spi_probe,
};
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index e850853328f1..4c448f39bf57 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -237,7 +238,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
static void ad7879_timer(struct timer_list *t)
{
- struct ad7879 *ts = from_timer(ts, t, timer);
+ struct ad7879 *ts = timer_container_of(ts, t, timer);
ad7879_ts_event_release(ts);
}
@@ -273,7 +274,7 @@ static void __ad7879_disable(struct ad7879 *ts)
AD7879_PM(AD7879_PM_SHUTDOWN);
disable_irq(ts->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7879_ts_event_release(ts);
ad7879_write(ts, AD7879_REG_CTRL2, reg);
@@ -391,6 +392,12 @@ static const struct attribute_group ad7879_attr_group = {
.attrs = ad7879_attributes,
};
+const struct attribute_group *ad7879_groups[] = {
+ &ad7879_attr_group,
+ NULL
+};
+EXPORT_SYMBOL_GPL(ad7879_groups);
+
#ifdef CONFIG_GPIOLIB
static int ad7879_gpio_direction_input(struct gpio_chip *chip,
unsigned gpio)
@@ -438,10 +445,11 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
return !!(val & AD7879_GPIO_DATA);
}
-static void ad7879_gpio_set_value(struct gpio_chip *chip,
- unsigned gpio, int value)
+static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
+ int value)
{
struct ad7879 *ts = gpiochip_get_data(chip);
+ int ret;
mutex_lock(&ts->mutex);
if (value)
@@ -449,8 +457,10 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
- ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ ret = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
+
+ return ret;
}
static int ad7879_gpio_add(struct ad7879 *ts)
@@ -612,10 +622,6 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
__ad7879_disable(ts);
- err = devm_device_add_group(dev, &ad7879_attr_group);
- if (err)
- return err;
-
err = ad7879_gpio_add(ts);
if (err)
return err;
diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h
index ae8aa1428e56..d71a8e787290 100644
--- a/drivers/input/touchscreen/ad7879.h
+++ b/drivers/input/touchscreen/ad7879.h
@@ -8,11 +8,14 @@
#ifndef _AD7879_H_
#define _AD7879_H_
+#include <linux/pm.h>
#include <linux/types.h>
+struct attribute_group;
struct device;
struct regmap;
+extern const struct attribute_group *ad7879_groups[];
extern const struct dev_pm_ops ad7879_pm_ops;
int ad7879_probe(struct device *dev, struct regmap *regmap,
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index bed68a68f330..67264c5b49cb 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -24,15 +24,13 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/pm.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
-#include <linux/gpio.h>
+#include <linux/property.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/*
* This code has been heavily tested on a Nokia 770, and lightly
@@ -139,7 +137,8 @@ struct ads7846 {
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
int (*get_pendown_state)(void);
- int gpio_pendown;
+ struct gpio_desc *gpio_pendown;
+ struct gpio_desc *gpio_hsync;
void (*wait_for_sync)(void);
};
@@ -222,7 +221,7 @@ static int get_pendown_state(struct ads7846 *ts)
if (ts->get_pendown_state)
return ts->get_pendown_state();
- return !gpio_get_value(ts->gpio_pendown);
+ return gpiod_get_value(ts->gpio_pendown);
}
static void ads7846_report_pen_up(struct ads7846 *ts)
@@ -332,7 +331,7 @@ struct ser_req {
u8 ref_off;
u16 scratch;
struct spi_message msg;
- struct spi_transfer xfer[6];
+ struct spi_transfer xfer[8];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -406,9 +405,19 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
req->xfer[5].rx_buf = &req->scratch;
req->xfer[5].len = 2;
- CS_CHANGE(req->xfer[5]);
spi_message_add_tail(&req->xfer[5], &req->msg);
+ /* clear the command register */
+ req->scratch = 0;
+ req->xfer[6].tx_buf = &req->scratch;
+ req->xfer[6].len = 1;
+ spi_message_add_tail(&req->xfer[6], &req->msg);
+
+ req->xfer[7].rx_buf = &req->scratch;
+ req->xfer[7].len = 2;
+ CS_CHANGE(req->xfer[7]);
+ spi_message_add_tail(&req->xfer[7], &req->msg);
+
mutex_lock(&ts->lock);
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
@@ -627,22 +636,15 @@ static ssize_t ads7846_disable_store(struct device *dev,
static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
-static struct attribute *ads784x_attributes[] = {
+static struct attribute *ads784x_attrs[] = {
&dev_attr_pen_down.attr,
&dev_attr_disable.attr,
NULL,
};
-
-static const struct attribute_group ads784x_attr_group = {
- .attrs = ads784x_attributes,
-};
+ATTRIBUTE_GROUPS(ads784x);
/*--------------------------------------------------------------------------*/
-static void null_wait_for_sync(void)
-{
-}
-
static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
{
struct ads7846 *ts = ads;
@@ -795,6 +797,28 @@ static int ads7846_filter(struct ads7846 *ts)
return 0;
}
+static void ads7846_wait_for_hsync(struct ads7846 *ts)
+{
+ if (ts->wait_for_sync) {
+ ts->wait_for_sync();
+ return;
+ }
+
+ if (!ts->gpio_hsync)
+ return;
+
+ /*
+ * Wait for HSYNC to assert the line should be flagged
+ * as active low so here we are waiting for it to assert
+ */
+ while (!gpiod_get_value(ts->gpio_hsync))
+ cpu_relax();
+
+ /* Then we wait for it do de-assert */
+ while (gpiod_get_value(ts->gpio_hsync))
+ cpu_relax();
+}
+
static void ads7846_read_state(struct ads7846 *ts)
{
struct ads7846_packet *packet = ts->packet;
@@ -805,12 +829,12 @@ static void ads7846_read_state(struct ads7846 *ts)
packet->last_cmd_idx = 0;
while (true) {
- ts->wait_for_sync();
+ ads7846_wait_for_hsync(ts);
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
- dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+ dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->ignore = true;
return;
}
@@ -843,14 +867,8 @@ static void ads7846_report_state(struct ads7846 *ts)
if (x == MAX_12BIT)
x = 0;
- if (ts->model == 7843) {
+ if (ts->model == 7843 || ts->model == 7845) {
Rt = ts->pressure_max / 2;
- } else if (ts->model == 7845) {
- if (get_pendown_state(ts))
- Rt = ts->pressure_max / 2;
- else
- Rt = 0;
- dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
} else if (likely(x && z1)) {
/* compute touch pressure resistance using equation #2 */
Rt = z2;
@@ -944,7 +962,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
return IRQ_HANDLED;
}
-static int __maybe_unused ads7846_suspend(struct device *dev)
+static int ads7846_suspend(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
@@ -966,7 +984,7 @@ static int __maybe_unused ads7846_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ads7846_resume(struct device *dev)
+static int ads7846_resume(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
@@ -988,14 +1006,12 @@ static int __maybe_unused ads7846_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
static int ads7846_setup_pendown(struct spi_device *spi,
struct ads7846 *ts,
const struct ads7846_platform_data *pdata)
{
- int err;
-
/*
* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
@@ -1004,25 +1020,15 @@ static int ads7846_setup_pendown(struct spi_device *spi,
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
- } else if (gpio_is_valid(pdata->gpio_pendown)) {
-
- err = devm_gpio_request_one(&spi->dev, pdata->gpio_pendown,
- GPIOF_IN, "ads7846_pendown");
- if (err) {
- dev_err(&spi->dev,
- "failed to request/setup pendown GPIO%d: %d\n",
- pdata->gpio_pendown, err);
- return err;
+ } else {
+ ts->gpio_pendown = devm_gpiod_get(&spi->dev, "pendown", GPIOD_IN);
+ if (IS_ERR(ts->gpio_pendown)) {
+ dev_err(&spi->dev, "failed to request pendown GPIO\n");
+ return PTR_ERR(ts->gpio_pendown);
}
-
- ts->gpio_pendown = pdata->gpio_pendown;
-
if (pdata->gpio_pendown_debounce)
- gpio_set_debounce(pdata->gpio_pendown,
- pdata->gpio_pendown_debounce);
- } else {
- dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
- return -EINVAL;
+ gpiod_set_debounce(ts->gpio_pendown,
+ pdata->gpio_pendown_debounce);
}
return 0;
@@ -1066,6 +1072,9 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
unsigned int max_count;
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
if (ads7846_cmd_need_settle(cmd_idx))
max_count = packet->count + packet->count_skip;
else
@@ -1102,7 +1111,12 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
- u8 cmd = ads7846_get_cmd(cmd_idx, vref);
+ u8 cmd;
+
+ if (cmd_idx == packet->cmds - 1)
+ cmd_idx = ADS7846_PWDOWN;
+
+ cmd = ads7846_get_cmd(cmd_idx, vref);
for (b = 0; b < l->count; b++)
packet->tx[l->offset + b].cmd = cmd;
@@ -1116,7 +1130,6 @@ static int ads7846_setup_spi_msg(struct ads7846 *ts,
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id ads7846_dt_ids[] = {
{ .compatible = "ti,tsc2046", .data = (void *) 7846 },
{ .compatible = "ti,ads7843", .data = (void *) 7843 },
@@ -1127,82 +1140,70 @@ static const struct of_device_id ads7846_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, ads7846_dt_ids);
-static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
+static const struct spi_device_id ads7846_spi_ids[] = {
+ { "tsc2046", 7846 },
+ { "ads7843", 7843 },
+ { "ads7845", 7845 },
+ { "ads7846", 7846 },
+ { "ads7873", 7873 },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, ads7846_spi_ids);
+
+static const struct ads7846_platform_data *ads7846_get_props(struct device *dev)
{
struct ads7846_platform_data *pdata;
- struct device_node *node = dev->of_node;
- const struct of_device_id *match;
u32 value;
- if (!node) {
- dev_err(dev, "Device does not have associated DT data\n");
- return ERR_PTR(-EINVAL);
- }
-
- match = of_match_device(ads7846_dt_ids, dev);
- if (!match) {
- dev_err(dev, "Unknown device model\n");
- return ERR_PTR(-EINVAL);
- }
-
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->model = (unsigned long)match->data;
+ pdata->model = (uintptr_t)device_get_match_data(dev);
- of_property_read_u16(node, "ti,vref-delay-usecs",
- &pdata->vref_delay_usecs);
- of_property_read_u16(node, "ti,vref-mv", &pdata->vref_mv);
- pdata->keep_vref_on = of_property_read_bool(node, "ti,keep-vref-on");
+ device_property_read_u16(dev, "ti,vref-delay-usecs",
+ &pdata->vref_delay_usecs);
+ device_property_read_u16(dev, "ti,vref-mv", &pdata->vref_mv);
+ pdata->keep_vref_on = device_property_read_bool(dev, "ti,keep-vref-on");
- pdata->swap_xy = of_property_read_bool(node, "ti,swap-xy");
+ pdata->swap_xy = device_property_read_bool(dev, "ti,swap-xy");
- of_property_read_u16(node, "ti,settle-delay-usec",
- &pdata->settle_delay_usecs);
- of_property_read_u16(node, "ti,penirq-recheck-delay-usecs",
- &pdata->penirq_recheck_delay_usecs);
+ device_property_read_u16(dev, "ti,settle-delay-usec",
+ &pdata->settle_delay_usecs);
+ device_property_read_u16(dev, "ti,penirq-recheck-delay-usecs",
+ &pdata->penirq_recheck_delay_usecs);
- of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms);
- of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms);
+ device_property_read_u16(dev, "ti,x-plate-ohms", &pdata->x_plate_ohms);
+ device_property_read_u16(dev, "ti,y-plate-ohms", &pdata->y_plate_ohms);
- of_property_read_u16(node, "ti,x-min", &pdata->x_min);
- of_property_read_u16(node, "ti,y-min", &pdata->y_min);
- of_property_read_u16(node, "ti,x-max", &pdata->x_max);
- of_property_read_u16(node, "ti,y-max", &pdata->y_max);
+ device_property_read_u16(dev, "ti,x-min", &pdata->x_min);
+ device_property_read_u16(dev, "ti,y-min", &pdata->y_min);
+ device_property_read_u16(dev, "ti,x-max", &pdata->x_max);
+ device_property_read_u16(dev, "ti,y-max", &pdata->y_max);
/*
* touchscreen-max-pressure gets parsed during
* touchscreen_parse_properties()
*/
- of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
- if (!of_property_read_u32(node, "touchscreen-min-pressure", &value))
+ device_property_read_u16(dev, "ti,pressure-min", &pdata->pressure_min);
+ if (!device_property_read_u32(dev, "touchscreen-min-pressure", &value))
pdata->pressure_min = (u16) value;
- of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
+ device_property_read_u16(dev, "ti,pressure-max", &pdata->pressure_max);
- of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
- if (!of_property_read_u32(node, "touchscreen-average-samples", &value))
+ device_property_read_u16(dev, "ti,debounce-max", &pdata->debounce_max);
+ if (!device_property_read_u32(dev, "touchscreen-average-samples", &value))
pdata->debounce_max = (u16) value;
- of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
- of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
+ device_property_read_u16(dev, "ti,debounce-tol", &pdata->debounce_tol);
+ device_property_read_u16(dev, "ti,debounce-rep", &pdata->debounce_rep);
- of_property_read_u32(node, "ti,pendown-gpio-debounce",
+ device_property_read_u32(dev, "ti,pendown-gpio-debounce",
&pdata->gpio_pendown_debounce);
- pdata->wakeup = of_property_read_bool(node, "wakeup-source") ||
- of_property_read_bool(node, "linux,wakeup");
-
- pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0);
+ pdata->wakeup = device_property_read_bool(dev, "wakeup-source") ||
+ device_property_read_bool(dev, "linux,wakeup");
return pdata;
}
-#else
-static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
-{
- dev_err(dev, "no platform data defined\n");
- return ERR_PTR(-EINVAL);
-}
-#endif
static void ads7846_regulator_disable(void *regulator)
{
@@ -1266,7 +1267,7 @@ static int ads7846_probe(struct spi_device *spi)
pdata = dev_get_platdata(dev);
if (!pdata) {
- pdata = ads7846_probe_dt(dev);
+ pdata = ads7846_get_props(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
@@ -1296,7 +1297,11 @@ static int ads7846_probe(struct spi_device *spi)
ts->penirq_recheck_delay_usecs =
pdata->penirq_recheck_delay_usecs;
- ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+ ts->wait_for_sync = pdata->wait_for_sync;
+
+ ts->gpio_hsync = devm_gpiod_get_optional(dev, "ti,hsync", GPIOD_IN);
+ if (IS_ERR(ts->gpio_hsync))
+ return PTR_ERR(ts->gpio_hsync);
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
@@ -1316,8 +1321,9 @@ static int ads7846_probe(struct spi_device *spi)
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE,
- pdata->pressure_min, pdata->pressure_max, 0, 0);
+ if (ts->model != 7845)
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ pdata->pressure_min, pdata->pressure_max, 0, 0);
/*
* Parse common framework properties. Must be done here to ensure the
@@ -1391,10 +1397,6 @@ static int ads7846_probe(struct spi_device *spi)
else
(void) ads7846_read12_ser(dev, READ_12BIT_SER(vaux));
- err = devm_device_add_group(dev, &ads784x_attr_group);
- if (err)
- return err;
-
err = input_register_device(input_dev);
if (err)
return err;
@@ -1420,16 +1422,17 @@ static void ads7846_remove(struct spi_device *spi)
static struct spi_driver ads7846_driver = {
.driver = {
- .name = "ads7846",
- .pm = &ads7846_pm,
- .of_match_table = of_match_ptr(ads7846_dt_ids),
+ .name = "ads7846",
+ .dev_groups = ads784x_groups,
+ .pm = pm_sleep_ptr(&ads7846_pm),
+ .of_match_table = ads7846_dt_ids,
},
.probe = ads7846_probe,
.remove = ads7846_remove,
+ .id_table = ads7846_spi_ids,
};
module_spi_driver(ads7846_driver);
MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:ads7846");
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
new file mode 100644
index 000000000000..0de161eae59a
--- /dev/null
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Z2 touchscreen driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+
+#define APPLE_Z2_NUM_FINGERS_OFFSET 16
+#define APPLE_Z2_FINGERS_OFFSET 24
+#define APPLE_Z2_TOUCH_STARTED 3
+#define APPLE_Z2_TOUCH_MOVED 4
+#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
+#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
+#define APPLE_Z2_FW_MAGIC 0x5746325A
+#define LOAD_COMMAND_INIT_PAYLOAD 0
+#define LOAD_COMMAND_SEND_BLOB 1
+#define LOAD_COMMAND_SEND_CALIBRATION 2
+#define CAL_PROP_NAME "apple,z2-cal-blob"
+
+struct apple_z2 {
+ struct spi_device *spidev;
+ struct gpio_desc *reset_gpio;
+ struct input_dev *input_dev;
+ struct completion boot_irq;
+ bool booted;
+ int index_parity;
+ struct touchscreen_properties props;
+ const char *fw_name;
+ u8 *tx_buf;
+ u8 *rx_buf;
+};
+
+struct apple_z2_finger {
+ u8 finger;
+ u8 state;
+ __le16 unknown2;
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 rel_x;
+ __le16 rel_y;
+ __le16 tool_major;
+ __le16 tool_minor;
+ __le16 orientation;
+ __le16 touch_major;
+ __le16 touch_minor;
+ __le16 unused[2];
+ __le16 pressure;
+ __le16 multi;
+} __packed;
+
+struct apple_z2_hbpp_blob_hdr {
+ __le16 cmd;
+ __le16 len;
+ __le32 addr;
+ __le16 checksum;
+};
+
+struct apple_z2_fw_hdr {
+ __le32 magic;
+ __le32 version;
+};
+
+struct apple_z2_read_interrupt_cmd {
+ u8 cmd;
+ u8 counter;
+ u8 unused[12];
+ __le16 checksum;
+};
+
+static void apple_z2_parse_touches(struct apple_z2 *z2,
+ const u8 *msg, size_t msg_len)
+{
+ int i;
+ int nfingers;
+ int slot;
+ int slot_valid;
+ struct apple_z2_finger *fingers;
+
+ if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET)
+ return;
+ nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
+ fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ for (i = 0; i < nfingers; i++) {
+ slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
+ if (slot < 0) {
+ dev_warn(&z2->spidev->dev, "unable to get slot for finger\n");
+ continue;
+ }
+ slot_valid = fingers[i].state == APPLE_Z2_TOUCH_STARTED ||
+ fingers[i].state == APPLE_Z2_TOUCH_MOVED;
+ input_mt_slot(z2->input_dev, slot);
+ if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid))
+ continue;
+ touchscreen_report_pos(z2->input_dev, &z2->props,
+ le16_to_cpu(fingers[i].abs_x),
+ le16_to_cpu(fingers[i].abs_y),
+ true);
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MAJOR,
+ le16_to_cpu(fingers[i].tool_major));
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR,
+ le16_to_cpu(fingers[i].tool_minor));
+ input_report_abs(z2->input_dev, ABS_MT_ORIENTATION,
+ le16_to_cpu(fingers[i].orientation));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR,
+ le16_to_cpu(fingers[i].touch_major));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MINOR,
+ le16_to_cpu(fingers[i].touch_minor));
+ }
+ input_mt_sync_frame(z2->input_dev);
+ input_sync(z2->input_dev);
+}
+
+static int apple_z2_read_packet(struct apple_z2 *z2)
+{
+ struct apple_z2_read_interrupt_cmd *len_cmd = (void *)z2->tx_buf;
+ struct spi_transfer xfer;
+ int error;
+ size_t pkt_len;
+
+ memset(&xfer, 0, sizeof(xfer));
+ len_cmd->cmd = APPLE_Z2_CMD_READ_INTERRUPT_DATA;
+ len_cmd->counter = z2->index_parity + 1;
+ len_cmd->checksum =
+ cpu_to_le16(APPLE_Z2_CMD_READ_INTERRUPT_DATA + len_cmd->counter);
+ z2->index_parity = !z2->index_parity;
+ xfer.tx_buf = z2->tx_buf;
+ xfer.rx_buf = z2->rx_buf;
+ xfer.len = sizeof(*len_cmd);
+
+ error = spi_sync_transfer(z2->spidev, &xfer, 1);
+ if (error)
+ return error;
+
+ pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
+
+ error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
+ if (error)
+ return error;
+
+ apple_z2_parse_touches(z2, z2->rx_buf + 5, pkt_len - 5);
+
+ return 0;
+}
+
+static irqreturn_t apple_z2_irq(int irq, void *data)
+{
+ struct apple_z2 *z2 = data;
+
+ if (unlikely(!z2->booted))
+ complete(&z2->boot_irq);
+ else
+ apple_z2_read_packet(z2);
+
+ return IRQ_HANDLED;
+}
+
+/* Build calibration blob, caller is responsible for freeing the blob data. */
+static const u8 *apple_z2_build_cal_blob(struct apple_z2 *z2,
+ u32 address, size_t *size)
+{
+ u8 *cal_data;
+ int cal_size;
+ size_t blob_size;
+ u32 checksum;
+ u16 checksum_hdr;
+ int i;
+ struct apple_z2_hbpp_blob_hdr *hdr;
+ int error;
+
+ if (!device_property_present(&z2->spidev->dev, CAL_PROP_NAME))
+ return NULL;
+
+ cal_size = device_property_count_u8(&z2->spidev->dev, CAL_PROP_NAME);
+ if (cal_size < 0)
+ return ERR_PTR(cal_size);
+
+ blob_size = sizeof(struct apple_z2_hbpp_blob_hdr) + cal_size + sizeof(__le32);
+ u8 *blob_data __free(kfree) = kzalloc(blob_size, GFP_KERNEL);
+ if (!blob_data)
+ return ERR_PTR(-ENOMEM);
+
+ hdr = (struct apple_z2_hbpp_blob_hdr *)blob_data;
+ hdr->cmd = cpu_to_le16(APPLE_Z2_HBPP_CMD_BLOB);
+ hdr->len = cpu_to_le16(round_up(cal_size, 4) / 4);
+ hdr->addr = cpu_to_le32(address);
+
+ checksum_hdr = 0;
+ for (i = 2; i < 8; i++)
+ checksum_hdr += blob_data[i];
+ hdr->checksum = cpu_to_le16(checksum_hdr);
+
+ cal_data = blob_data + sizeof(struct apple_z2_hbpp_blob_hdr);
+ error = device_property_read_u8_array(&z2->spidev->dev, CAL_PROP_NAME,
+ cal_data, cal_size);
+ if (error)
+ return ERR_PTR(error);
+
+ checksum = 0;
+ for (i = 0; i < cal_size; i++)
+ checksum += cal_data[i];
+ put_unaligned_le32(checksum, cal_data + cal_size);
+
+ *size = blob_size;
+ return no_free_ptr(blob_data);
+}
+
+static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
+ u32 size, bool init)
+{
+ struct spi_message msg;
+ struct spi_transfer blob_xfer, ack_xfer;
+ int error;
+
+ z2->tx_buf[0] = 0x1a;
+ z2->tx_buf[1] = 0xa1;
+
+ spi_message_init(&msg);
+ memset(&blob_xfer, 0, sizeof(blob_xfer));
+ memset(&ack_xfer, 0, sizeof(ack_xfer));
+
+ blob_xfer.tx_buf = data;
+ blob_xfer.len = size;
+ blob_xfer.bits_per_word = init ? 8 : 16;
+ spi_message_add_tail(&blob_xfer, &msg);
+
+ ack_xfer.tx_buf = z2->tx_buf;
+ ack_xfer.len = 2;
+ spi_message_add_tail(&ack_xfer, &msg);
+
+ reinit_completion(&z2->boot_irq);
+ error = spi_sync(z2->spidev, &msg);
+ if (error)
+ return error;
+
+ /* Irq only happens sometimes, but the thing boots reliably nonetheless */
+ wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20));
+
+ return 0;
+}
+
+static int apple_z2_upload_firmware(struct apple_z2 *z2)
+{
+ const struct apple_z2_fw_hdr *fw_hdr;
+ size_t fw_idx = sizeof(struct apple_z2_fw_hdr);
+ int error;
+ u32 load_cmd;
+ u32 address;
+ bool init;
+ size_t size;
+
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_firmware(&fw, z2->fw_name, &z2->spidev->dev);
+ if (error) {
+ dev_err(&z2->spidev->dev, "unable to load firmware\n");
+ return error;
+ }
+
+ fw_hdr = (const struct apple_z2_fw_hdr *)fw->data;
+ if (le32_to_cpu(fw_hdr->magic) != APPLE_Z2_FW_MAGIC || le32_to_cpu(fw_hdr->version) != 1) {
+ dev_err(&z2->spidev->dev, "invalid firmware header\n");
+ return -EINVAL;
+ }
+
+ /*
+ * This will interrupt the upload half-way if the file is malformed
+ * As the device has no non-volatile storage to corrupt, and gets reset
+ * on boot anyway, this is fine.
+ */
+ while (fw_idx < fw->size) {
+ if (fw->size - fw_idx < 8) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+
+ load_cmd = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (load_cmd == LOAD_COMMAND_INIT_PAYLOAD || load_cmd == LOAD_COMMAND_SEND_BLOB) {
+ size = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (fw->size - fw_idx < size) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ init = load_cmd == LOAD_COMMAND_INIT_PAYLOAD;
+ error = apple_z2_send_firmware_blob(z2, fw->data + fw_idx,
+ size, init);
+ if (error)
+ return error;
+ fw_idx += size;
+ } else if (load_cmd == LOAD_COMMAND_SEND_CALIBRATION) {
+ address = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+
+ const u8 *data __free(kfree) =
+ apple_z2_build_cal_blob(z2, address, &size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (data) {
+ error = apple_z2_send_firmware_blob(z2, data, size, false);
+ if (error)
+ return error;
+ }
+ } else {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ fw_idx = round_up(fw_idx, 4);
+ }
+
+
+ z2->booted = true;
+ apple_z2_read_packet(z2);
+ return 0;
+}
+
+static int apple_z2_boot(struct apple_z2 *z2)
+{
+ int error;
+
+ reinit_completion(&z2->boot_irq);
+ enable_irq(z2->spidev->irq);
+ gpiod_set_value(z2->reset_gpio, 0);
+ if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)))
+ return -ETIMEDOUT;
+
+ error = apple_z2_upload_firmware(z2);
+ if (error) {
+ gpiod_set_value(z2->reset_gpio, 1);
+ disable_irq(z2->spidev->irq);
+ return error;
+ }
+
+ return 0;
+}
+
+static int apple_z2_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct apple_z2 *z2;
+ int error;
+
+ z2 = devm_kzalloc(dev, sizeof(*z2), GFP_KERNEL);
+ if (!z2)
+ return -ENOMEM;
+
+ z2->tx_buf = devm_kzalloc(dev, sizeof(struct apple_z2_read_interrupt_cmd), GFP_KERNEL);
+ if (!z2->tx_buf)
+ return -ENOMEM;
+ /* 4096 will end up being rounded up to 8192 due to devres header */
+ z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
+ if (!z2->rx_buf)
+ return -ENOMEM;
+
+ z2->spidev = spi;
+ init_completion(&z2->boot_irq);
+ spi_set_drvdata(spi, z2);
+
+ /* Reset the device on boot */
+ z2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(z2->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(z2->reset_gpio), "unable to get reset\n");
+
+ error = devm_request_threaded_irq(dev, z2->spidev->irq, NULL, apple_z2_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ "apple-z2-irq", z2);
+ if (error)
+ return dev_err_probe(dev, error, "unable to request irq\n");
+
+ error = device_property_read_string(dev, "firmware-name", &z2->fw_name);
+ if (error)
+ return dev_err_probe(dev, error, "unable to get firmware name\n");
+
+ z2->input_dev = devm_input_allocate_device(dev);
+ if (!z2->input_dev)
+ return -ENOMEM;
+
+ z2->input_dev->name = (char *)spi_get_device_id(spi)->driver_data;
+ z2->input_dev->phys = "apple_z2";
+ z2->input_dev->id.bustype = BUS_SPI;
+
+ /* Allocate the axes before setting from DT */
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_X, 0, 0, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_Y, 0, 0, 0, 0);
+ touchscreen_parse_properties(z2->input_dev, true, &z2->props);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_X, 100);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_Y, 100);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_ORIENTATION, -32768, 32767, 0, 0);
+
+ error = input_mt_init_slots(z2->input_dev, 256, INPUT_MT_DIRECT);
+ if (error)
+ return dev_err_probe(dev, error, "unable to initialize multitouch slots\n");
+
+ error = input_register_device(z2->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "unable to register input device\n");
+
+ /* Wait for device reset to finish */
+ usleep_range(5000, 10000);
+ error = apple_z2_boot(z2);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void apple_z2_shutdown(struct spi_device *spi)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(spi);
+
+ disable_irq(z2->spidev->irq);
+ gpiod_direction_output(z2->reset_gpio, 1);
+ z2->booted = false;
+}
+
+static int apple_z2_suspend(struct device *dev)
+{
+ apple_z2_shutdown(to_spi_device(dev));
+
+ return 0;
+}
+
+static int apple_z2_resume(struct device *dev)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(to_spi_device(dev));
+
+ return apple_z2_boot(z2);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(apple_z2_pm, apple_z2_suspend, apple_z2_resume);
+
+static const struct of_device_id apple_z2_of_match[] = {
+ { .compatible = "apple,j293-touchbar" },
+ { .compatible = "apple,j493-touchbar" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_z2_of_match);
+
+static struct spi_device_id apple_z2_of_id[] = {
+ { .name = "j293-touchbar", .driver_data = (kernel_ulong_t)"MacBookPro17,1 Touch Bar" },
+ { .name = "j493-touchbar", .driver_data = (kernel_ulong_t)"Mac14,7 Touch Bar" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, apple_z2_of_id);
+
+static struct spi_driver apple_z2_driver = {
+ .driver = {
+ .name = "apple-z2",
+ .pm = pm_sleep_ptr(&apple_z2_pm),
+ .of_match_table = apple_z2_of_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = apple_z2_of_id,
+ .probe = apple_z2_probe,
+ .remove = apple_z2_shutdown,
+};
+
+module_spi_driver(apple_z2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("apple/dfrmtfw-*.bin");
+MODULE_DESCRIPTION("Apple Z2 touchscreens driver");
diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c
index 25bcc677e98b..8a588202447d 100644
--- a/drivers/input/touchscreen/ar1021_i2c.c
+++ b/drivers/input/touchscreen/ar1021_i2c.c
@@ -142,7 +142,7 @@ static int ar1021_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused ar1021_i2c_suspend(struct device *dev)
+static int ar1021_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -151,7 +151,7 @@ static int __maybe_unused ar1021_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ar1021_i2c_resume(struct device *dev)
+static int ar1021_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -160,11 +160,12 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm,
+ ar1021_i2c_suspend, ar1021_i2c_resume);
static const struct i2c_device_id ar1021_i2c_id[] = {
- { "ar1021", 0 },
- { },
+ { "ar1021" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
@@ -177,11 +178,11 @@ MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match);
static struct i2c_driver ar1021_i2c_driver = {
.driver = {
.name = "ar1021_i2c",
- .pm = &ar1021_i2c_pm,
+ .pm = pm_sleep_ptr(&ar1021_i2c_pm),
.of_match_table = ar1021_i2c_of_match,
},
- .probe_new = ar1021_i2c_probe,
+ .probe = ar1021_i2c_probe,
.id_table = ar1021_i2c_id,
};
module_i2c_driver(ar1021_i2c_driver);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 39ef2664b852..dd0544cc1bc1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -19,6 +19,7 @@
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
@@ -26,7 +27,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
@@ -55,6 +56,7 @@
#define MXT_TOUCH_KEYARRAY_T15 15
#define MXT_TOUCH_PROXIMITY_T23 23
#define MXT_TOUCH_PROXKEY_T52 52
+#define MXT_TOUCH_PTC_KEYS_T97 97
#define MXT_PROCI_GRIPFACE_T20 20
#define MXT_PROCG_NOISE_T22 22
#define MXT_PROCI_ONETOUCH_T24 24
@@ -326,9 +328,13 @@ struct mxt_data {
u16 T71_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
+ u8 T15_reportid_min;
+ u8 T15_reportid_max;
u16 T18_address;
u8 T19_reportid;
u16 T44_address;
+ u8 T97_reportid_min;
+ u8 T97_reportid_max;
u8 T100_reportid_min;
u8 T100_reportid_max;
@@ -344,9 +350,14 @@ struct mxt_data {
u32 *t19_keymap;
unsigned int t19_num_keys;
+ u32 *t15_keymap;
+ unsigned int t15_num_keys;
+
enum mxt_suspend_mode suspend_mode;
u32 wakeup_method;
+
+ struct touchscreen_properties prop;
};
struct mxt_vb2_buffer {
@@ -375,6 +386,7 @@ static bool mxt_object_readable(unsigned int type)
case MXT_TOUCH_KEYARRAY_T15:
case MXT_TOUCH_PROXIMITY_T23:
case MXT_TOUCH_PROXKEY_T52:
+ case MXT_TOUCH_PTC_KEYS_T97:
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
case MXT_PROCI_GRIPFACE_T20:
case MXT_PROCG_NOISE_T22:
@@ -879,8 +891,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
/* Touch active */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
} else {
@@ -891,6 +902,24 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
data->update_input = true;
}
+static void mxt_proc_t15_messages(struct mxt_data *data, u8 *message)
+{
+ struct input_dev *input_dev = data->input_dev;
+ unsigned long keystates = get_unaligned_le32(&message[2]);
+ int key;
+
+ for (key = 0; key < data->t15_num_keys; key++)
+ input_report_key(input_dev, data->t15_keymap[key],
+ keystates & BIT(key));
+
+ data->update_input = true;
+}
+
+static void mxt_proc_t97_messages(struct mxt_data *data, u8 *message)
+{
+ mxt_proc_t15_messages(data, message);
+}
+
static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
{
struct device *dev = &data->client->dev;
@@ -983,8 +1012,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
id, type, x, y, major, pressure, orientation);
input_mt_report_slot_state(input_dev, tool, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
@@ -1017,6 +1045,12 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message)
} else if (report_id >= data->T9_reportid_min &&
report_id <= data->T9_reportid_max) {
mxt_proc_t9_message(data, message);
+ } else if (report_id >= data->T15_reportid_min &&
+ report_id <= data->T15_reportid_max) {
+ mxt_proc_t15_messages(data, message);
+ } else if (report_id >= data->T97_reportid_min &&
+ report_id <= data->T97_reportid_max) {
+ mxt_proc_t97_messages(data, message);
} else if (report_id >= data->T100_reportid_min &&
report_id <= data->T100_reportid_max) {
mxt_proc_t100_message(data, message);
@@ -1689,9 +1723,13 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T71_address = 0;
data->T9_reportid_min = 0;
data->T9_reportid_max = 0;
+ data->T15_reportid_min = 0;
+ data->T15_reportid_max = 0;
data->T18_address = 0;
data->T19_reportid = 0;
data->T44_address = 0;
+ data->T97_reportid_min = 0;
+ data->T97_reportid_max = 0;
data->T100_reportid_min = 0;
data->T100_reportid_max = 0;
data->max_reportid = 0;
@@ -1764,6 +1802,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
object->num_report_ids - 1;
data->num_touchids = object->num_report_ids;
break;
+ case MXT_TOUCH_KEYARRAY_T15:
+ data->T15_reportid_min = min_id;
+ data->T15_reportid_max = max_id;
+ break;
case MXT_SPT_COMMSCONFIG_T18:
data->T18_address = object->start_address;
break;
@@ -1773,6 +1815,10 @@ static int mxt_parse_object_table(struct mxt_data *data,
case MXT_SPT_GPIOPWM_T19:
data->T19_reportid = min_id;
break;
+ case MXT_TOUCH_PTC_KEYS_T97:
+ data->T97_reportid_min = min_id;
+ data->T97_reportid_max = max_id;
+ break;
case MXT_TOUCH_MULTITOUCHSCREEN_T100:
data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100;
data->T100_reportid_min = min_id;
@@ -2050,6 +2096,7 @@ static int mxt_initialize_input_device(struct mxt_data *data)
int error;
unsigned int num_mt_slots;
unsigned int mt_flags = 0;
+ int i;
switch (data->multitouch) {
case MXT_TOUCH_MULTI_T9:
@@ -2095,6 +2142,10 @@ static int mxt_initialize_input_device(struct mxt_data *data)
input_dev->open = mxt_input_open;
input_dev->close = mxt_input_close;
+ input_dev->keycode = data->t15_keymap;
+ input_dev->keycodemax = data->t15_num_keys;
+ input_dev->keycodesize = sizeof(data->t15_keymap[0]);
+
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
/* For single touch */
@@ -2162,6 +2213,15 @@ static int mxt_initialize_input_device(struct mxt_data *data)
0, 255, 0, 0);
}
+ touchscreen_parse_properties(input_dev, true, &data->prop);
+
+ /* For T15 and T97 Key Array */
+ if (data->T15_reportid_min || data->T97_reportid_min) {
+ for (i = 0; i < data->t15_num_keys; i++)
+ input_set_capability(input_dev,
+ EV_KEY, data->t15_keymap[i]);
+ }
+
input_set_drvdata(input_dev, data);
error = input_register_device(input_dev);
@@ -2478,8 +2538,6 @@ fault:
static const struct vb2_ops mxt_queue_ops = {
.queue_setup = mxt_queue_setup,
.buf_queue = mxt_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue mxt_queue = {
@@ -2489,7 +2547,7 @@ static const struct vb2_queue mxt_queue = {
.ops = &mxt_queue_ops,
.mem_ops = &vb2_vmalloc_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
- .min_buffers_needed = 1,
+ .min_queued_buffers = 1,
};
static int mxt_vidioc_querycap(struct file *file, void *priv,
@@ -2761,8 +2819,8 @@ static ssize_t mxt_fw_version_show(struct device *dev,
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_info *info = data->info;
- return scnprintf(buf, PAGE_SIZE, "%u.%u.%02X\n",
- info->version >> 4, info->version & 0xf, info->build);
+ return sysfs_emit(buf, "%u.%u.%02X\n",
+ info->version >> 4, info->version & 0xf, info->build);
}
/* Hardware Version is returned as FamilyID.VariantID */
@@ -2771,8 +2829,7 @@ static ssize_t mxt_hw_version_show(struct device *dev,
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_info *info = data->info;
- return scnprintf(buf, PAGE_SIZE, "%u.%u\n",
- info->family_id, info->variant_id);
+ return sysfs_emit(buf, "%u.%u\n", info->family_id, info->variant_id);
}
static ssize_t mxt_show_instance(char *buf, int count,
@@ -2782,19 +2839,18 @@ static ssize_t mxt_show_instance(char *buf, int count,
int i;
if (mxt_obj_instances(object) > 1)
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Instance %u\n", instance);
+ count += sysfs_emit_at(buf, count, "Instance %u\n", instance);
for (i = 0; i < mxt_obj_size(object); i++)
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "\t[%2u]: %02x (%d)\n", i, val[i], val[i]);
- count += scnprintf(buf + count, PAGE_SIZE - count, "\n");
+ count += sysfs_emit_at(buf, count, "\t[%2u]: %02x (%d)\n",
+ i, val[i], val[i]);
+ count += sysfs_emit_at(buf, count, "\n");
return count;
}
static ssize_t mxt_object_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+ struct device_attribute *attr, char *buf)
{
struct mxt_data *data = dev_get_drvdata(dev);
struct mxt_object *object;
@@ -2815,8 +2871,7 @@ static ssize_t mxt_object_show(struct device *dev,
if (!mxt_object_readable(object->type))
continue;
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "T%u:\n", object->type);
+ count += sysfs_emit_at(buf, count, "T%u:\n", object->type);
for (j = 0; j < mxt_obj_instances(object); j++) {
u16 size = mxt_obj_size(object);
@@ -3015,9 +3070,7 @@ static struct attribute *mxt_attrs[] = {
NULL
};
-static const struct attribute_group mxt_attr_group = {
- .attrs = mxt_attrs,
-};
+ATTRIBUTE_GROUPS(mxt);
static void mxt_start(struct mxt_data *data)
{
@@ -3080,8 +3133,10 @@ static void mxt_input_close(struct input_dev *dev)
static int mxt_parse_device_properties(struct mxt_data *data)
{
static const char keymap_property[] = "linux,gpio-keymap";
+ static const char buttons_property[] = "linux,keycodes";
struct device *dev = &data->client->dev;
u32 *keymap;
+ u32 *buttonmap;
int n_keys;
int error;
@@ -3111,6 +3166,32 @@ static int mxt_parse_device_properties(struct mxt_data *data)
data->t19_num_keys = n_keys;
}
+ if (device_property_present(dev, buttons_property)) {
+ n_keys = device_property_count_u32(dev, buttons_property);
+ if (n_keys <= 0) {
+ error = n_keys < 0 ? n_keys : -EINVAL;
+ dev_err(dev, "invalid/malformed '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap),
+ GFP_KERNEL);
+ if (!buttonmap)
+ return -ENOMEM;
+
+ error = device_property_read_u32_array(dev, buttons_property,
+ buttonmap, n_keys);
+ if (error) {
+ dev_err(dev, "failed to parse '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ data->t15_keymap = buttonmap;
+ data->t15_num_keys = n_keys;
+ }
+
return 0;
}
@@ -3239,7 +3320,7 @@ static int mxt_probe(struct i2c_client *client)
if (data->reset_gpio) {
/* Wait a while and then de-assert the RESET GPIO line */
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 0);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
msleep(MXT_RESET_INVALID_CHG);
}
@@ -3266,18 +3347,8 @@ static int mxt_probe(struct i2c_client *client)
if (error)
goto err_disable_regulators;
- error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
- if (error) {
- dev_err(&client->dev, "Failure %d creating sysfs group\n",
- error);
- goto err_free_object;
- }
-
return 0;
-err_free_object:
- mxt_free_input_device(data);
- mxt_free_object_table(data);
err_disable_regulators:
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
@@ -3289,14 +3360,13 @@ static void mxt_remove(struct i2c_client *client)
struct mxt_data *data = i2c_get_clientdata(client);
disable_irq(data->irq);
- sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
mxt_free_input_device(data);
mxt_free_object_table(data);
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
}
-static int __maybe_unused mxt_suspend(struct device *dev)
+static int mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3317,7 +3387,7 @@ static int __maybe_unused mxt_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mxt_resume(struct device *dev)
+static int mxt_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mxt_data *data = i2c_get_clientdata(client);
@@ -3338,7 +3408,7 @@ static int __maybe_unused mxt_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
static const struct of_device_id mxt_of_match[] = {
{ .compatible = "atmel,maxtouch", },
@@ -3361,11 +3431,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
#endif
static const struct i2c_device_id mxt_id[] = {
- { "qt602240_ts", 0 },
- { "atmel_mxt_ts", 0 },
- { "atmel_mxt_tp", 0 },
- { "maxtouch", 0 },
- { "mXT224", 0 },
+ { "qt602240_ts" },
+ { "atmel_mxt_ts" },
+ { "atmel_mxt_tp" },
+ { "maxtouch" },
+ { "mXT224" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mxt_id);
@@ -3373,11 +3443,12 @@ MODULE_DEVICE_TABLE(i2c, mxt_id);
static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
+ .dev_groups = mxt_groups,
.of_match_table = mxt_of_match,
.acpi_match_table = ACPI_PTR(mxt_acpi_id),
- .pm = &mxt_pm_ops,
+ .pm = pm_sleep_ptr(&mxt_pm_ops),
},
- .probe_new = mxt_probe,
+ .probe = mxt_probe,
.remove = mxt_remove,
.id_table = mxt_id,
};
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index a4a1d58aeeac..363a4a1f1560 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -72,7 +72,7 @@
/*
* Interrupt modes:
- * periodical: interrupt is asserted periodicaly
+ * periodical: interrupt is asserted periodically
* compare coordinates: interrupt is asserted when coordinates change
* indicate touch: interrupt is asserted during touch
*/
@@ -410,7 +410,7 @@ static void auo_pixcir_input_close(struct input_dev *dev)
auo_pixcir_stop(ts);
}
-static int __maybe_unused auo_pixcir_suspend(struct device *dev)
+static int auo_pixcir_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
@@ -442,7 +442,7 @@ unlock:
return ret;
}
-static int __maybe_unused auo_pixcir_resume(struct device *dev)
+static int auo_pixcir_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
@@ -472,8 +472,8 @@ unlock:
return ret;
}
-static SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
- auo_pixcir_suspend, auo_pixcir_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,
+ auo_pixcir_suspend, auo_pixcir_resume);
static void auo_pixcir_reset(void *data)
{
@@ -617,7 +617,7 @@ static int auo_pixcir_probe(struct i2c_client *client)
}
static const struct i2c_device_id auo_pixcir_idtable[] = {
- { "auo_pixcir_ts", 0 },
+ { "auo_pixcir_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
@@ -633,10 +633,10 @@ MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable);
static struct i2c_driver auo_pixcir_driver = {
.driver = {
.name = "auo_pixcir_ts",
- .pm = &auo_pixcir_pm_ops,
+ .pm = pm_sleep_ptr(&auo_pixcir_pm_ops),
.of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable),
},
- .probe_new = auo_pixcir_probe,
+ .probe = auo_pixcir_probe,
.id_table = auo_pixcir_idtable,
};
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
index 35e2fe9911a4..e49bde50d77a 100644
--- a/drivers/input/touchscreen/bcm_iproc_tsc.c
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -217,7 +217,7 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
"pen up-down (%d)\n", priv->pen_status);
}
- /* coordinates in FIFO exceed the theshold */
+ /* coordinates in FIFO exceed the threshold */
if (intr_status & TS_FIFO_INTR_MASK) {
for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
regmap_read(priv->regmap, FIFO_DATA, &raw_coordinate);
@@ -511,7 +511,7 @@ static struct platform_driver iproc_ts_driver = {
.probe = iproc_ts_probe,
.driver = {
.name = IPROC_TS_NAME,
- .of_match_table = of_match_ptr(iproc_ts_of_match),
+ .of_match_table = iproc_ts_of_match,
},
};
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index 5a4dbd39a372..6baebb7ec089 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -410,31 +410,32 @@ static int bu21013_probe(struct i2c_client *client)
struct input_dev *in_dev;
struct input_absinfo *info;
u32 max_x = 0, max_y = 0;
+ struct device *dev = &client->dev;
int error;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev, "i2c smbus byte data not supported\n");
+ dev_err(dev, "i2c smbus byte data not supported\n");
return -EIO;
}
if (!client->irq) {
- dev_err(&client->dev, "No IRQ set up\n");
+ dev_err(dev, "No IRQ set up\n");
return -EINVAL;
}
- ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
if (!ts)
return -ENOMEM;
ts->client = client;
- ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x");
- ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y");
+ ts->x_flip = device_property_read_bool(dev, "rohm,flip-x");
+ ts->y_flip = device_property_read_bool(dev, "rohm,flip-y");
- in_dev = devm_input_allocate_device(&client->dev);
+ in_dev = devm_input_allocate_device(dev);
if (!in_dev) {
- dev_err(&client->dev, "device memory alloc failed\n");
+ dev_err(dev, "device memory alloc failed\n");
return -ENOMEM;
}
ts->in_dev = in_dev;
@@ -444,8 +445,8 @@ static int bu21013_probe(struct i2c_client *client)
in_dev->name = DRIVER_TP;
in_dev->id.bustype = BUS_I2C;
- device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x);
- device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y);
+ device_property_read_u32(dev, "rohm,touch-max-x", &max_x);
+ device_property_read_u32(dev, "rohm,touch-max-y", &max_y);
input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);
input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
@@ -454,14 +455,14 @@ static int bu21013_probe(struct i2c_client *client)
/* Adjust for the legacy "flip" properties, if present */
if (!ts->props.invert_x &&
- device_property_read_bool(&client->dev, "rohm,flip-x")) {
+ device_property_read_bool(dev, "rohm,flip-x")) {
info = &in_dev->absinfo[ABS_MT_POSITION_X];
info->maximum -= info->minimum;
info->minimum = 0;
}
if (!ts->props.invert_y &&
- device_property_read_bool(&client->dev, "rohm,flip-y")) {
+ device_property_read_bool(dev, "rohm,flip-y")) {
info = &in_dev->absinfo[ABS_MT_POSITION_Y];
info->maximum -= info->minimum;
info->minimum = 0;
@@ -471,55 +472,46 @@ static int bu21013_probe(struct i2c_client *client)
INPUT_MT_DIRECT | INPUT_MT_TRACK |
INPUT_MT_DROP_UNUSED);
if (error) {
- dev_err(&client->dev, "failed to initialize MT slots");
+ dev_err(dev, "failed to initialize MT slots");
return error;
}
- ts->regulator = devm_regulator_get(&client->dev, "avdd");
+ ts->regulator = devm_regulator_get(dev, "avdd");
if (IS_ERR(ts->regulator)) {
- dev_err(&client->dev, "regulator_get failed\n");
+ dev_err(dev, "regulator_get failed\n");
return PTR_ERR(ts->regulator);
}
error = regulator_enable(ts->regulator);
if (error) {
- dev_err(&client->dev, "regulator enable failed\n");
+ dev_err(dev, "regulator enable failed\n");
return error;
}
- error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts);
+ error = devm_add_action_or_reset(dev, bu21013_power_off, ts);
if (error) {
- dev_err(&client->dev, "failed to install power off handler\n");
+ dev_err(dev, "failed to install power off handler\n");
return error;
}
/* Named "CS" on the chip, DT binding is "reset" */
- ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
- error = PTR_ERR_OR_ZERO(ts->cs_gpiod);
- if (error) {
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev, "failed to get CS GPIO\n");
- return error;
- }
+ ts->cs_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ts->cs_gpiod))
+ return dev_err_probe(dev, PTR_ERR(ts->cs_gpiod), "failed to get CS GPIO\n");
+
gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS");
- error = devm_add_action_or_reset(&client->dev,
- bu21013_disable_chip, ts);
+ error = devm_add_action_or_reset(dev, bu21013_disable_chip, ts);
if (error) {
- dev_err(&client->dev,
- "failed to install chip disable handler\n");
+ dev_err(dev, "failed to install chip disable handler\n");
return error;
}
/* Named "INT" on the chip, DT binding is "touch" */
- ts->int_gpiod = devm_gpiod_get_optional(&client->dev,
- "touch", GPIOD_IN);
+ ts->int_gpiod = devm_gpiod_get_optional(dev, "touch", GPIOD_IN);
error = PTR_ERR_OR_ZERO(ts->int_gpiod);
- if (error) {
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev, "failed to get INT GPIO\n");
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "failed to get INT GPIO\n");
if (ts->int_gpiod)
gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT");
@@ -527,22 +519,20 @@ static int bu21013_probe(struct i2c_client *client)
/* configure the touch panel controller */
error = bu21013_init_chip(ts);
if (error) {
- dev_err(&client->dev, "error in bu21013 config\n");
+ dev_err(dev, "error in bu21013 config\n");
return error;
}
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, bu21013_gpio_irq,
+ error = devm_request_threaded_irq(dev, client->irq, NULL, bu21013_gpio_irq,
IRQF_ONESHOT, DRIVER_TP, ts);
if (error) {
- dev_err(&client->dev, "request irq %d failed\n",
- client->irq);
+ dev_err(dev, "request irq %d failed\n", client->irq);
return error;
}
error = input_register_device(in_dev);
if (error) {
- dev_err(&client->dev, "failed to register input device\n");
+ dev_err(dev, "failed to register input device\n");
return error;
}
@@ -560,7 +550,7 @@ static void bu21013_remove(struct i2c_client *client)
/* The resources will be freed by devm */
}
-static int __maybe_unused bu21013_suspend(struct device *dev)
+static int bu21013_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bu21013_ts *ts = i2c_get_clientdata(client);
@@ -575,7 +565,7 @@ static int __maybe_unused bu21013_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bu21013_resume(struct device *dev)
+static int bu21013_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bu21013_ts *ts = i2c_get_clientdata(client);
@@ -604,10 +594,10 @@ static int __maybe_unused bu21013_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
static const struct i2c_device_id bu21013_id[] = {
- { DRIVER_TP, 0 },
+ { DRIVER_TP },
{ }
};
MODULE_DEVICE_TABLE(i2c, bu21013_id);
@@ -615,9 +605,9 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id);
static struct i2c_driver bu21013_driver = {
.driver = {
.name = DRIVER_TP,
- .pm = &bu21013_dev_pm_ops,
+ .pm = pm_sleep_ptr(&bu21013_dev_pm_ops),
},
- .probe_new = bu21013_probe,
+ .probe = bu21013_probe,
.remove = bu21013_remove,
.id_table = bu21013_id,
};
diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c
index 215f4dc5105d..64f474e67312 100644
--- a/drivers/input/touchscreen/bu21029_ts.c
+++ b/drivers/input/touchscreen/bu21029_ts.c
@@ -209,7 +209,8 @@ static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf)
static void bu21029_touch_release(struct timer_list *t)
{
- struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer);
+ struct bu21029_ts_data *bu21029 = timer_container_of(bu21029, t,
+ timer);
input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0);
input_report_key(bu21029->in_dev, BTN_TOUCH, 0);
@@ -325,7 +326,7 @@ static void bu21029_stop_chip(struct input_dev *dev)
struct bu21029_ts_data *bu21029 = input_get_drvdata(dev);
disable_irq(bu21029->client->irq);
- del_timer_sync(&bu21029->timer);
+ timer_delete_sync(&bu21029->timer);
bu21029_put_chip_in_reset(bu21029);
regulator_disable(bu21029->vdd);
@@ -333,6 +334,7 @@ static void bu21029_stop_chip(struct input_dev *dev)
static int bu21029_probe(struct i2c_client *client)
{
+ struct device *dev = &client->dev;
struct bu21029_ts_data *bu21029;
struct input_dev *in_dev;
int error;
@@ -341,45 +343,33 @@ static int bu21029_probe(struct i2c_client *client)
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- dev_err(&client->dev,
- "i2c functionality support is not sufficient\n");
+ dev_err(dev, "i2c functionality support is not sufficient\n");
return -EIO;
}
- bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL);
+ bu21029 = devm_kzalloc(dev, sizeof(*bu21029), GFP_KERNEL);
if (!bu21029)
return -ENOMEM;
- error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms",
- &bu21029->x_plate_ohms);
+ error = device_property_read_u32(dev, "rohm,x-plate-ohms", &bu21029->x_plate_ohms);
if (error) {
- dev_err(&client->dev,
- "invalid 'x-plate-ohms' supplied: %d\n", error);
+ dev_err(dev, "invalid 'x-plate-ohms' supplied: %d\n", error);
return error;
}
- bu21029->vdd = devm_regulator_get(&client->dev, "vdd");
- if (IS_ERR(bu21029->vdd)) {
- error = PTR_ERR(bu21029->vdd);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "failed to acquire 'vdd' supply: %d\n", error);
- return error;
- }
+ bu21029->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(bu21029->vdd))
+ return dev_err_probe(dev, PTR_ERR(bu21029->vdd),
+ "failed to acquire 'vdd' supply\n");
- bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev,
- "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(bu21029->reset_gpios)) {
- error = PTR_ERR(bu21029->reset_gpios);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "failed to acquire 'reset' gpio: %d\n", error);
- return error;
- }
+ bu21029->reset_gpios = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(bu21029->reset_gpios))
+ return dev_err_probe(dev, PTR_ERR(bu21029->reset_gpios),
+ "failed to acquire 'reset' gpio\n");
- in_dev = devm_input_allocate_device(&client->dev);
+ in_dev = devm_input_allocate_device(dev);
if (!in_dev) {
- dev_err(&client->dev, "unable to allocate input device\n");
+ dev_err(dev, "unable to allocate input device\n");
return -ENOMEM;
}
@@ -400,20 +390,18 @@ static int bu21029_probe(struct i2c_client *client)
input_set_drvdata(in_dev, bu21029);
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, bu21029_touch_soft_irq,
+ error = devm_request_threaded_irq(dev, client->irq, NULL,
+ bu21029_touch_soft_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
DRIVER_NAME, bu21029);
if (error) {
- dev_err(&client->dev,
- "unable to request touch irq: %d\n", error);
+ dev_err(dev, "unable to request touch irq: %d\n", error);
return error;
}
error = input_register_device(in_dev);
if (error) {
- dev_err(&client->dev,
- "unable to register input device: %d\n", error);
+ dev_err(dev, "unable to register input device: %d\n", error);
return error;
}
@@ -422,7 +410,7 @@ static int bu21029_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused bu21029_suspend(struct device *dev)
+static int bu21029_suspend(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
@@ -437,7 +425,7 @@ static int __maybe_unused bu21029_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bu21029_resume(struct device *dev)
+static int bu21029_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
@@ -451,10 +439,10 @@ static int __maybe_unused bu21029_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
static const struct i2c_device_id bu21029_ids[] = {
- { DRIVER_NAME, 0 },
+ { DRIVER_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, bu21029_ids);
@@ -471,10 +459,10 @@ static struct i2c_driver bu21029_driver = {
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(bu21029_of_ids),
- .pm = &bu21029_pm_ops,
+ .pm = pm_sleep_ptr(&bu21029_pm_ops),
},
.id_table = bu21029_ids,
- .probe_new = bu21029_probe,
+ .probe = bu21029_probe,
};
module_i2c_driver(bu21029_driver);
diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c
index f6769e4bd4f2..d6876d10b252 100644
--- a/drivers/input/touchscreen/chipone_icn8318.c
+++ b/drivers/input/touchscreen/chipone_icn8318.c
@@ -148,7 +148,6 @@ static void icn8318_stop(struct input_dev *dev)
gpiod_set_value_cansleep(data->wake_gpio, 0);
}
-#ifdef CONFIG_PM_SLEEP
static int icn8318_suspend(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
@@ -172,9 +171,8 @@ static int icn8318_resume(struct device *dev)
return 0;
}
-#endif
-static SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(icn8318_pm_ops, icn8318_suspend, icn8318_resume);
static int icn8318_probe(struct i2c_client *client)
{
@@ -193,12 +191,8 @@ static int icn8318_probe(struct i2c_client *client)
return -ENOMEM;
data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW);
- if (IS_ERR(data->wake_gpio)) {
- error = PTR_ERR(data->wake_gpio);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Error getting wake gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(data->wake_gpio))
+ return dev_err_probe(dev, PTR_ERR(data->wake_gpio), "Error getting wake gpio\n");
input = devm_input_allocate_device(dev);
if (!input)
@@ -263,10 +257,10 @@ MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id);
static struct i2c_driver icn8318_driver = {
.driver = {
.name = "chipone_icn8318",
- .pm = &icn8318_pm_ops,
+ .pm = pm_sleep_ptr(&icn8318_pm_ops),
.of_match_table = icn8318_of_match,
},
- .probe_new = icn8318_probe,
+ .probe = icn8318_probe,
.id_table = icn8318_i2c_id,
};
diff --git a/drivers/input/touchscreen/chipone_icn8505.c b/drivers/input/touchscreen/chipone_icn8505.c
index c421f4be2700..cde0e4789503 100644
--- a/drivers/input/touchscreen/chipone_icn8505.c
+++ b/drivers/input/touchscreen/chipone_icn8505.c
@@ -8,7 +8,7 @@
* Hans de Goede <hdegoede@redhat.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/acpi.h>
#include <linux/crc32.h>
#include <linux/delay.h>
@@ -68,7 +68,6 @@ struct icn8505_touch_data {
struct icn8505_data {
struct i2c_client *client;
struct input_dev *input;
- struct gpio_desc *wake_gpio;
struct touchscreen_properties prop;
char firmware_name[32];
};
@@ -460,7 +459,7 @@ static int icn8505_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused icn8505_suspend(struct device *dev)
+static int icn8505_suspend(struct device *dev)
{
struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev));
@@ -471,7 +470,7 @@ static int __maybe_unused icn8505_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused icn8505_resume(struct device *dev)
+static int icn8505_resume(struct device *dev)
{
struct icn8505_data *icn8505 = i2c_get_clientdata(to_i2c_client(dev));
int error;
@@ -484,7 +483,7 @@ static int __maybe_unused icn8505_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(icn8505_pm_ops, icn8505_suspend, icn8505_resume);
static const struct acpi_device_id icn8505_acpi_match[] = {
{ "CHPN0001" },
@@ -495,10 +494,10 @@ MODULE_DEVICE_TABLE(acpi, icn8505_acpi_match);
static struct i2c_driver icn8505_driver = {
.driver = {
.name = "chipone_icn8505",
- .pm = &icn8505_pm_ops,
+ .pm = pm_sleep_ptr(&icn8505_pm_ops),
.acpi_match_table = icn8505_acpi_match,
},
- .probe_new = icn8505_probe,
+ .probe = icn8505_probe,
};
module_i2c_driver(icn8505_driver);
diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c
index aa829725ded7..98d5b2ba63fb 100644
--- a/drivers/input/touchscreen/colibri-vf50-ts.c
+++ b/drivers/input/touchscreen/colibri-vf50-ts.c
@@ -239,14 +239,10 @@ static void vf50_ts_close(struct input_dev *dev_input)
static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d,
const char *con_id, enum gpiod_flags flags)
{
- int error;
-
*gpio_d = devm_gpiod_get(dev, con_id, flags);
- if (IS_ERR(*gpio_d)) {
- error = PTR_ERR(*gpio_d);
- dev_err(dev, "Could not get gpio_%s %d\n", con_id, error);
- return error;
- }
+ if (IS_ERR(*gpio_d))
+ return dev_err_probe(dev, PTR_ERR(*gpio_d),
+ "Could not get gpio_%s\n", con_id);
return 0;
}
diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c
index 3a91d948b7f6..2d4b6e343203 100644
--- a/drivers/input/touchscreen/cy8ctma140.c
+++ b/drivers/input/touchscreen/cy8ctma140.c
@@ -16,7 +16,7 @@
* same.
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
@@ -258,12 +258,8 @@ static int cy8ctma140_probe(struct i2c_client *client)
ts->regulators[1].supply = "vdd";
error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
ts->regulators);
- if (error) {
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get regulators %d\n",
- error);
- return error;
- }
+ if (error)
+ return dev_err_probe(dev, error, "Failed to get regulators\n");
error = cy8ctma140_power_up(ts);
if (error)
@@ -296,7 +292,7 @@ static int cy8ctma140_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused cy8ctma140_suspend(struct device *dev)
+static int cy8ctma140_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctma140 *ts = i2c_get_clientdata(client);
@@ -307,7 +303,7 @@ static int __maybe_unused cy8ctma140_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cy8ctma140_resume(struct device *dev)
+static int cy8ctma140_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctma140 *ts = i2c_get_clientdata(client);
@@ -322,10 +318,11 @@ static int __maybe_unused cy8ctma140_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cy8ctma140_pm, cy8ctma140_suspend, cy8ctma140_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm,
+ cy8ctma140_suspend, cy8ctma140_resume);
static const struct i2c_device_id cy8ctma140_idtable[] = {
- { CY8CTMA140_NAME, 0 },
+ { CY8CTMA140_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable);
@@ -339,11 +336,11 @@ MODULE_DEVICE_TABLE(of, cy8ctma140_of_match);
static struct i2c_driver cy8ctma140_driver = {
.driver = {
.name = CY8CTMA140_NAME,
- .pm = &cy8ctma140_pm,
+ .pm = pm_sleep_ptr(&cy8ctma140_pm),
.of_match_table = cy8ctma140_of_match,
},
.id_table = cy8ctma140_idtable,
- .probe_new = cy8ctma140_probe,
+ .probe = cy8ctma140_probe,
};
module_i2c_driver(cy8ctma140_driver);
diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c
index 7c2b7309dbaf..54d6c4869eb0 100644
--- a/drivers/input/touchscreen/cy8ctmg110_ts.c
+++ b/drivers/input/touchscreen/cy8ctmg110_ts.c
@@ -237,7 +237,7 @@ static int cy8ctmg110_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
+static int cy8ctmg110_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
@@ -250,7 +250,7 @@ static int __maybe_unused cy8ctmg110_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused cy8ctmg110_resume(struct device *dev)
+static int cy8ctmg110_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cy8ctmg110 *ts = i2c_get_clientdata(client);
@@ -263,7 +263,8 @@ static int __maybe_unused cy8ctmg110_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(cy8ctmg110_pm, cy8ctmg110_suspend, cy8ctmg110_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm,
+ cy8ctmg110_suspend, cy8ctmg110_resume);
static const struct i2c_device_id cy8ctmg110_idtable[] = {
{ CY8CTMG110_DRIVER_NAME, 1 },
@@ -275,10 +276,10 @@ MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable);
static struct i2c_driver cy8ctmg110_driver = {
.driver = {
.name = CY8CTMG110_DRIVER_NAME,
- .pm = &cy8ctmg110_pm,
+ .pm = pm_sleep_ptr(&cy8ctmg110_pm),
},
.id_table = cy8ctmg110_idtable,
- .probe_new = cy8ctmg110_probe,
+ .probe = cy8ctmg110_probe,
};
module_i2c_driver(cy8ctmg110_driver);
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
deleted file mode 100644
index dccbcb942fe5..000000000000
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ /dev/null
@@ -1,2180 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp4_core.c
- * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2012 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/input/mt.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-/* Timeout in ms. */
-#define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500
-#define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000
-#define CY_CORE_MODE_CHANGE_TIMEOUT 1000
-#define CY_CORE_RESET_AND_WAIT_TIMEOUT 500
-#define CY_CORE_WAKEUP_TIMEOUT 500
-
-#define CY_CORE_STARTUP_RETRY_COUNT 3
-
-static const char * const cyttsp4_tch_abs_string[] = {
- [CY_TCH_X] = "X",
- [CY_TCH_Y] = "Y",
- [CY_TCH_P] = "P",
- [CY_TCH_T] = "T",
- [CY_TCH_E] = "E",
- [CY_TCH_O] = "O",
- [CY_TCH_W] = "W",
- [CY_TCH_MAJ] = "MAJ",
- [CY_TCH_MIN] = "MIN",
- [CY_TCH_OR] = "OR",
- [CY_TCH_NUM_ABS] = "INVALID"
-};
-
-static const u8 ldr_exit[] = {
- 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
-};
-
-static const u8 ldr_err_app[] = {
- 0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17
-};
-
-static inline size_t merge_bytes(u8 high, u8 low)
-{
- return (high << 8) + low;
-}
-
-#ifdef VERBOSE_DEBUG
-static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
- const char *data_name)
-{
- int i, k;
- const char fmt[] = "%02X ";
- int max;
-
- if (!size)
- return;
-
- max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
-
- pr_buf[0] = 0;
- for (i = k = 0; i < size && k < max; i++, k += 3)
- scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
-
- dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1,
- pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
-}
-#else
-#define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0)
-#endif
-
-static int cyttsp4_load_status_regs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- struct device *dev = cd->dev;
- int rc;
-
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size,
- si->xy_mode);
- if (rc < 0)
- dev_err(dev, "%s: fail read mode regs r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode,
- si->si_ofs.mode_size, "xy_mode");
-
- return rc;
-}
-
-static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode)
-{
- u8 cmd = mode ^ CY_HST_TOGGLE;
- int rc;
-
- /*
- * Mode change issued, handshaking now will cause endless mode change
- * requests, for sync mode modechange will do same with handshake
- * */
- if (mode & CY_HST_MODE_CHANGE)
- return 0;
-
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
- if (rc < 0)
- dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n",
- __func__, rc);
-
- return rc;
-}
-
-static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd)
-{
- u8 cmd = CY_HST_RESET;
- int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
- __func__);
- return rc;
- }
- return 0;
-}
-
-static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd)
-{
- if (cd->cpdata->xres) {
- cd->cpdata->xres(cd->cpdata, cd->dev);
- dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__);
- return 0;
- }
- dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
- return -ENOSYS;
-}
-
-static int cyttsp4_hw_reset(struct cyttsp4 *cd)
-{
- int rc = cyttsp4_hw_hard_reset(cd);
- if (rc == -ENOSYS)
- rc = cyttsp4_hw_soft_reset(cd);
- return rc;
-}
-
-/*
- * Gets number of bits for a touch filed as parameter,
- * sets maximum value for field which is used as bit mask
- * and returns number of bytes required for that field
- */
-static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max)
-{
- *max = 1UL << nbits;
- return (nbits + 7) / 8;
-}
-
-static int cyttsp4_si_data_offsets(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data),
- &si->si_data);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n",
- __func__, rc);
- return rc;
- }
-
- /* Print sysinfo data offsets */
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data,
- sizeof(si->si_data), "sysinfo_data_offsets");
-
- /* convert sysinfo data offset bytes into integers */
-
- si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
- si->si_data.map_szl);
- si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
- si->si_data.map_szl);
- si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh,
- si->si_data.cydata_ofsl);
- si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh,
- si->si_data.test_ofsl);
- si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh,
- si->si_data.pcfg_ofsl);
- si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh,
- si->si_data.opcfg_ofsl);
- si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh,
- si->si_data.ddata_ofsl);
- si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh,
- si->si_data.mdata_ofsl);
- return rc;
-}
-
-static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int read_offset;
- int mfgid_sz, calc_mfgid_sz;
- void *p;
- int rc;
-
- if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
- __func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
- dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
- si->si_ofs.cydata_size);
-
- p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.cydata = p;
-
- read_offset = si->si_ofs.cydata_ofs;
-
- /* Read the CYDA registers up to MFGID field */
- rc = cyttsp4_adap_read(cd, read_offset,
- offsetof(struct cyttsp4_cydata, mfgid_sz)
- + sizeof(si->si_ptrs.cydata->mfgid_sz),
- si->si_ptrs.cydata);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- /* Check MFGID size */
- mfgid_sz = si->si_ptrs.cydata->mfgid_sz;
- calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata);
- if (mfgid_sz != calc_mfgid_sz) {
- dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n",
- __func__, mfgid_sz, calc_mfgid_sz);
- return -EINVAL;
- }
-
- read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz)
- + sizeof(si->si_ptrs.cydata->mfgid_sz);
-
- /* Read the CYDA registers for MFGID field */
- rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz,
- si->si_ptrs.cydata->mfg_id);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- read_offset += si->si_ptrs.cydata->mfgid_sz;
-
- /* Read the rest of the CYDA registers */
- rc = cyttsp4_adap_read(cd, read_offset,
- sizeof(struct cyttsp4_cydata)
- - offsetof(struct cyttsp4_cydata, cyito_idh),
- &si->si_ptrs.cydata->cyito_idh);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata,
- si->si_ofs.cydata_size, "sysinfo_cydata");
- return rc;
-}
-
-static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
- __func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
-
- p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate test memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.test = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size,
- si->si_ptrs.test);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read test data r=%d\n",
- __func__, rc);
- return rc;
- }
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.test, si->si_ofs.test_size,
- "sysinfo_test_data");
- if (si->si_ptrs.test->post_codel &
- CY_POST_CODEL_WDG_RST)
- dev_info(cd->dev, "%s: %s codel=%02X\n",
- __func__, "Reset was a WATCHDOG RESET",
- si->si_ptrs.test->post_codel);
-
- if (!(si->si_ptrs.test->post_codel &
- CY_POST_CODEL_CFG_DATA_CRC_FAIL))
- dev_info(cd->dev, "%s: %s codel=%02X\n", __func__,
- "Config Data CRC FAIL",
- si->si_ptrs.test->post_codel);
-
- if (!(si->si_ptrs.test->post_codel &
- CY_POST_CODEL_PANEL_TEST_FAIL))
- dev_info(cd->dev, "%s: %s codel=%02X\n",
- __func__, "PANEL TEST FAIL",
- si->si_ptrs.test->post_codel);
-
- dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n",
- __func__, si->si_ptrs.test->post_codel & 0x08 ?
- "ENABLED" : "DISABLED",
- si->si_ptrs.test->post_codel);
- return rc;
-}
-
-static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
- __func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
-
- p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.pcfg = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size,
- si->si_ptrs.pcfg);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read pcfg data r=%d\n",
- __func__, rc);
- return rc;
- }
-
- si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh
- & CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl);
- si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh
- & CY_PCFG_ORIGIN_X_MASK);
- si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh
- & CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl);
- si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh
- & CY_PCFG_ORIGIN_Y_MASK);
- si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh,
- si->si_ptrs.pcfg->max_zl);
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.pcfg,
- si->si_ofs.pcfg_size, "sysinfo_pcfg_data");
- return rc;
-}
-
-static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- struct cyttsp4_tch_abs_params *tch;
- struct cyttsp4_tch_rec_params *tch_old, *tch_new;
- enum cyttsp4_tch_abs abs;
- int i;
- void *p;
- int rc;
-
- if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
- __func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
-
- p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.opcfg = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size,
- si->si_ptrs.opcfg);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
- __func__, rc);
- return rc;
- }
- si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
- si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
- si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) +
- si->si_ptrs.opcfg->rep_szl;
- si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns;
- si->si_ofs.num_btn_regs = (si->si_ofs.num_btns +
- CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG;
- si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs;
- si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0;
- si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs &
- CY_BYTE_OFS_MASK;
- si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size &
- CY_BYTE_OFS_MASK;
-
- /* Get the old touch fields */
- for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) {
- tch = &si->si_ofs.tch_abs[abs];
- tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs];
-
- tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK;
- tch->size = cyttsp4_bits_2_bytes(tch_old->size,
- &tch->max);
- tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
- }
-
- /* button fields */
- si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size;
- si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs;
- si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size;
-
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
- /* Get the extended touch fields */
- for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) {
- tch = &si->si_ofs.tch_abs[abs];
- tch_new = &si->si_ptrs.opcfg->tch_rec_new[i];
-
- tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK;
- tch->size = cyttsp4_bits_2_bytes(tch_new->size,
- &tch->max);
- tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
- }
- }
-
- for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) {
- dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__,
- cyttsp4_tch_abs_string[abs]);
- dev_dbg(cd->dev, "%s: ofs =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].ofs);
- dev_dbg(cd->dev, "%s: siz =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].size);
- dev_dbg(cd->dev, "%s: max =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].max);
- dev_dbg(cd->dev, "%s: bofs=%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].bofs);
- }
-
- si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1;
- si->si_ofs.data_size = si->si_ofs.max_tchs *
- si->si_ptrs.opcfg->tch_rec_size;
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
- si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
-
- return 0;
-}
-
-static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs;
-
- p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__);
- return -ENOMEM;
- }
- si->si_ptrs.ddata = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size,
- si->si_ptrs.ddata);
- if (rc < 0)
- dev_err(cd->dev, "%s: fail read ddata data r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.ddata,
- si->si_ofs.ddata_size, "sysinfo_ddata");
- return rc;
-}
-
-static int cyttsp4_si_get_mdata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs;
-
- p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__);
- return -ENOMEM;
- }
- si->si_ptrs.mdata = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size,
- si->si_ptrs.mdata);
- if (rc < 0)
- dev_err(cd->dev, "%s: fail read mdata data r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.mdata,
- si->si_ofs.mdata_size, "sysinfo_mdata");
- return rc;
-}
-
-static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int btn;
- int num_defined_keys;
- u16 *key_table;
- void *p;
- int rc = 0;
-
- if (si->si_ofs.num_btns) {
- si->si_ofs.btn_keys_size = si->si_ofs.num_btns *
- sizeof(struct cyttsp4_btn);
-
- p = krealloc(si->btn, si->si_ofs.btn_keys_size,
- GFP_KERNEL|__GFP_ZERO);
- if (p == NULL) {
- dev_err(cd->dev, "%s: %s\n", __func__,
- "fail alloc btn_keys memory");
- return -ENOMEM;
- }
- si->btn = p;
-
- if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL)
- num_defined_keys = 0;
- else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL)
- num_defined_keys = 0;
- else
- num_defined_keys = cd->cpdata->sett
- [CY_IC_GRPNUM_BTN_KEYS]->size;
-
- for (btn = 0; btn < si->si_ofs.num_btns &&
- btn < num_defined_keys; btn++) {
- key_table = (u16 *)cd->cpdata->sett
- [CY_IC_GRPNUM_BTN_KEYS]->data;
- si->btn[btn].key_code = key_table[btn];
- si->btn[btn].state = CY_BTN_RELEASED;
- si->btn[btn].enabled = true;
- }
- for (; btn < si->si_ofs.num_btns; btn++) {
- si->btn[btn].key_code = KEY_RESERVED;
- si->btn[btn].state = CY_BTN_RELEASED;
- si->btn[btn].enabled = true;
- }
-
- return rc;
- }
-
- si->si_ofs.btn_keys_size = 0;
- kfree(si->btn);
- si->btn = NULL;
- return rc;
-}
-
-static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
-
- p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->xy_mode = p;
-
- p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->xy_data = p;
-
- p = krealloc(si->btn_rec_data,
- si->si_ofs.btn_rec_size * si->si_ofs.num_btns,
- GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->btn_rec_data = p;
-
- return 0;
-}
-
-static void cyttsp4_si_put_log_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- dev_dbg(cd->dev, "%s: cydata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.cydata_ofs, si->si_ofs.cydata_size);
- dev_dbg(cd->dev, "%s: test_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.test_ofs, si->si_ofs.test_size);
- dev_dbg(cd->dev, "%s: pcfg_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size);
- dev_dbg(cd->dev, "%s: opcfg_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size);
- dev_dbg(cd->dev, "%s: ddata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.ddata_ofs, si->si_ofs.ddata_size);
- dev_dbg(cd->dev, "%s: mdata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.mdata_ofs, si->si_ofs.mdata_size);
-
- dev_dbg(cd->dev, "%s: cmd_ofs =%4zd\n", __func__,
- si->si_ofs.cmd_ofs);
- dev_dbg(cd->dev, "%s: rep_ofs =%4zd\n", __func__,
- si->si_ofs.rep_ofs);
- dev_dbg(cd->dev, "%s: rep_sz =%4zd\n", __func__,
- si->si_ofs.rep_sz);
- dev_dbg(cd->dev, "%s: num_btns =%4zd\n", __func__,
- si->si_ofs.num_btns);
- dev_dbg(cd->dev, "%s: num_btn_regs =%4zd\n", __func__,
- si->si_ofs.num_btn_regs);
- dev_dbg(cd->dev, "%s: tt_stat_ofs =%4zd\n", __func__,
- si->si_ofs.tt_stat_ofs);
- dev_dbg(cd->dev, "%s: tch_rec_size =%4zd\n", __func__,
- si->si_ofs.tch_rec_size);
- dev_dbg(cd->dev, "%s: max_tchs =%4zd\n", __func__,
- si->si_ofs.max_tchs);
- dev_dbg(cd->dev, "%s: mode_size =%4zd\n", __func__,
- si->si_ofs.mode_size);
- dev_dbg(cd->dev, "%s: data_size =%4zd\n", __func__,
- si->si_ofs.data_size);
- dev_dbg(cd->dev, "%s: map_sz =%4zd\n", __func__,
- si->si_ofs.map_sz);
-
- dev_dbg(cd->dev, "%s: btn_rec_size =%2zd\n", __func__,
- si->si_ofs.btn_rec_size);
- dev_dbg(cd->dev, "%s: btn_diff_ofs =%2zd\n", __func__,
- si->si_ofs.btn_diff_ofs);
- dev_dbg(cd->dev, "%s: btn_diff_size =%2zd\n", __func__,
- si->si_ofs.btn_diff_size);
-
- dev_dbg(cd->dev, "%s: max_x = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_x, si->si_ofs.max_x);
- dev_dbg(cd->dev, "%s: x_origin = %zd (%s)\n", __func__,
- si->si_ofs.x_origin,
- si->si_ofs.x_origin == CY_NORMAL_ORIGIN ?
- "left corner" : "right corner");
- dev_dbg(cd->dev, "%s: max_y = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_y, si->si_ofs.max_y);
- dev_dbg(cd->dev, "%s: y_origin = %zd (%s)\n", __func__,
- si->si_ofs.y_origin,
- si->si_ofs.y_origin == CY_NORMAL_ORIGIN ?
- "upper corner" : "lower corner");
- dev_dbg(cd->dev, "%s: max_p = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_p, si->si_ofs.max_p);
-
- dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__,
- si->xy_mode, si->xy_data);
-}
-
-static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int rc;
-
- rc = cyttsp4_si_data_offsets(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_cydata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_test_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_pcfg_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_opcfg_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_ddata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_mdata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_btn_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_op_data_ptrs(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to get_op_data\n",
- __func__);
- return rc;
- }
-
- cyttsp4_si_put_log_data(cd);
-
- /* provide flow control handshake */
- rc = cyttsp4_handshake(cd, si->si_data.hst_mode);
- if (rc < 0)
- dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n",
- __func__);
-
- si->ready = true;
- return rc;
-}
-
-static void cyttsp4_queue_startup_(struct cyttsp4 *cd)
-{
- if (cd->startup_state == STARTUP_NONE) {
- cd->startup_state = STARTUP_QUEUED;
- schedule_work(&cd->startup_work);
- dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__);
- } else {
- dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__,
- cd->startup_state);
- }
-}
-
-static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md,
- int max_slots)
-{
- int t;
-
- if (md->num_prv_tch == 0)
- return;
-
- for (t = 0; t < max_slots; t++) {
- input_mt_slot(md->input, t);
- input_mt_report_slot_inactive(md->input);
- }
-}
-
-static void cyttsp4_lift_all(struct cyttsp4_mt_data *md)
-{
- if (!md->si)
- return;
-
- if (md->num_prv_tch != 0) {
- cyttsp4_report_slot_liftoff(md,
- md->si->si_ofs.tch_abs[CY_TCH_T].max);
- input_sync(md->input);
- md->num_prv_tch = 0;
- }
-}
-
-static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md,
- int *axis, int size, int max, u8 *xy_data, int bofs)
-{
- int nbyte;
- int next;
-
- for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
- dev_vdbg(&md->input->dev,
- "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
- " xy_data[%d]=%02X(%d) bofs=%d\n",
- __func__, *axis, *axis, size, max, xy_data, next,
- xy_data[next], xy_data[next], bofs);
- *axis = (*axis * 256) + (xy_data[next] >> bofs);
- next++;
- }
-
- *axis &= max - 1;
-
- dev_vdbg(&md->input->dev,
- "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
- " xy_data[%d]=%02X(%d)\n",
- __func__, *axis, *axis, size, max, xy_data, next,
- xy_data[next], xy_data[next]);
-}
-
-static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
- struct cyttsp4_touch *touch, u8 *xy_data)
-{
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- enum cyttsp4_tch_abs abs;
- bool flipped;
-
- for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
- cyttsp4_get_touch_axis(md, &touch->abs[abs],
- si->si_ofs.tch_abs[abs].size,
- si->si_ofs.tch_abs[abs].max,
- xy_data + si->si_ofs.tch_abs[abs].ofs,
- si->si_ofs.tch_abs[abs].bofs);
- dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
- cyttsp4_tch_abs_string[abs],
- touch->abs[abs], touch->abs[abs]);
- }
-
- if (md->pdata->flags & CY_FLAG_FLIP) {
- swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
- flipped = true;
- } else
- flipped = false;
-
- if (md->pdata->flags & CY_FLAG_INV_X) {
- if (flipped)
- touch->abs[CY_TCH_X] = md->si->si_ofs.max_y -
- touch->abs[CY_TCH_X];
- else
- touch->abs[CY_TCH_X] = md->si->si_ofs.max_x -
- touch->abs[CY_TCH_X];
- }
- if (md->pdata->flags & CY_FLAG_INV_Y) {
- if (flipped)
- touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x -
- touch->abs[CY_TCH_Y];
- else
- touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y -
- touch->abs[CY_TCH_Y];
- }
-
- dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
- __func__, flipped ? "true" : "false",
- md->pdata->flags & CY_FLAG_INV_X ? "true" : "false",
- md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false",
- touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
- touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
-}
-
-static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids)
-{
- int t;
-
- for (t = 0; t < max_slots; t++) {
- if (ids[t])
- continue;
- input_mt_slot(input, t);
- input_mt_report_slot_inactive(input);
- }
-
- input_sync(input);
-}
-
-static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
-{
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- struct cyttsp4_touch tch;
- int sig;
- int i, j, t = 0;
- int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
-
- memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int));
- for (i = 0; i < num_cur_tch; i++) {
- cyttsp4_get_touch(md, &tch, si->xy_data +
- (i * si->si_ofs.tch_rec_size));
- if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) ||
- (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) {
- dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
- __func__, i, tch.abs[CY_TCH_T],
- md->pdata->frmwrk->abs[(CY_ABS_ID_OST *
- CY_NUM_ABS_SET) + CY_MAX_OST]);
- continue;
- }
-
- /* use 0 based track id's */
- sig = md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE) {
- t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST];
- if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) {
- dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
- __func__, t, tch.abs[CY_TCH_E]);
- goto cyttsp4_get_mt_touches_pr_tch;
- }
- input_mt_slot(md->input, t);
- input_mt_report_slot_state(md->input, MT_TOOL_FINGER,
- true);
- ids[t] = true;
- }
-
- /* all devices: position and pressure fields */
- for (j = 0; j <= CY_ABS_W_OST; j++) {
- sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) *
- CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE)
- input_report_abs(md->input, sig,
- tch.abs[CY_TCH_X + j]);
- }
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
- /*
- * TMA400 size and orientation fields:
- * if pressure is non-zero and major touch
- * signal is zero, then set major and minor touch
- * signals to minimum non-zero value
- */
- if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0)
- tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1;
-
- /* Get the extended touch fields */
- for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
- sig = md->pdata->frmwrk->abs
- [((CY_ABS_MAJ_OST + j) *
- CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE)
- input_report_abs(md->input, sig,
- tch.abs[CY_TCH_MAJ + j]);
- }
- }
-
-cyttsp4_get_mt_touches_pr_tch:
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE)
- dev_dbg(dev,
- "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n",
- __func__, t,
- tch.abs[CY_TCH_X],
- tch.abs[CY_TCH_Y],
- tch.abs[CY_TCH_P],
- tch.abs[CY_TCH_MAJ],
- tch.abs[CY_TCH_MIN],
- tch.abs[CY_TCH_OR],
- tch.abs[CY_TCH_E]);
- else
- dev_dbg(dev,
- "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__,
- t,
- tch.abs[CY_TCH_X],
- tch.abs[CY_TCH_Y],
- tch.abs[CY_TCH_P],
- tch.abs[CY_TCH_E]);
- }
-
- cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids);
-
- md->num_prv_tch = num_cur_tch;
-
- return;
-}
-
-/* read xy_data for all current touches */
-static int cyttsp4_xy_worker(struct cyttsp4 *cd)
-{
- struct cyttsp4_mt_data *md = &cd->md;
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- u8 num_cur_tch;
- u8 hst_mode;
- u8 rep_len;
- u8 rep_stat;
- u8 tt_stat;
- int rc = 0;
-
- /*
- * Get event data from cyttsp4 device.
- * The event data includes all data
- * for all active touches.
- * Event data also includes button data
- */
- /*
- * Use 2 reads:
- * 1st read to get mode + button bytes + touch count (core)
- * 2nd read (optional) to get touch 1 - touch n data
- */
- hst_mode = si->xy_mode[CY_REG_BASE];
- rep_len = si->xy_mode[si->si_ofs.rep_ofs];
- rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1];
- tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs];
- dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__,
- "hst_mode=", hst_mode, "rep_len=", rep_len,
- "rep_stat=", rep_stat, "tt_stat=", tt_stat);
-
- num_cur_tch = GET_NUM_TOUCHES(tt_stat);
- dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch);
-
- if (rep_len == 0 && num_cur_tch > 0) {
- dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n",
- __func__, rep_len, num_cur_tch);
- goto cyttsp4_xy_worker_exit;
- }
-
- /* read touches */
- if (num_cur_tch > 0) {
- rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1,
- num_cur_tch * si->si_ofs.tch_rec_size,
- si->xy_data);
- if (rc < 0) {
- dev_err(dev, "%s: read fail on touch regs r=%d\n",
- __func__, rc);
- goto cyttsp4_xy_worker_exit;
- }
- }
-
- /* print xy data */
- cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch *
- si->si_ofs.tch_rec_size, "xy_data");
-
- /* check any error conditions */
- if (IS_BAD_PKT(rep_stat)) {
- dev_dbg(dev, "%s: Invalid buffer detected\n", __func__);
- rc = 0;
- goto cyttsp4_xy_worker_exit;
- }
-
- if (IS_LARGE_AREA(tt_stat))
- dev_dbg(dev, "%s: Large area detected\n", __func__);
-
- if (num_cur_tch > si->si_ofs.max_tchs) {
- dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%zd)\n",
- __func__, num_cur_tch, si->si_ofs.max_tchs);
- num_cur_tch = si->si_ofs.max_tchs;
- }
-
- /* extract xy_data for all currently reported touches */
- dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
- num_cur_tch);
- if (num_cur_tch)
- cyttsp4_get_mt_touches(md, num_cur_tch);
- else
- cyttsp4_lift_all(md);
-
- rc = 0;
-
-cyttsp4_xy_worker_exit:
- return rc;
-}
-
-static int cyttsp4_mt_attention(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- int rc = 0;
-
- if (!md->si)
- return 0;
-
- mutex_lock(&md->report_lock);
- if (!md->is_suspended) {
- /* core handles handshake */
- rc = cyttsp4_xy_worker(cd);
- } else {
- dev_vdbg(dev, "%s: Ignoring report while suspended\n",
- __func__);
- }
- mutex_unlock(&md->report_lock);
- if (rc < 0)
- dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
-
- return rc;
-}
-
-static irqreturn_t cyttsp4_irq(int irq, void *handle)
-{
- struct cyttsp4 *cd = handle;
- struct device *dev = cd->dev;
- enum cyttsp4_mode cur_mode;
- u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs;
- u8 mode[3];
- int rc;
-
- /*
- * Check whether this IRQ should be ignored (external)
- * This should be the very first thing to check since
- * ignore_irq may be set for a very short period of time
- */
- if (atomic_read(&cd->ignore_irq)) {
- dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
- return IRQ_HANDLED;
- }
-
- dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status);
-
- mutex_lock(&cd->system_lock);
-
- /* Just to debug */
- if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING)
- dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__);
-
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode);
- if (rc) {
- dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
- goto cyttsp4_irq_exit;
- }
- dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__,
- mode[0], mode[1], mode[2]);
-
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- cur_mode = CY_MODE_BOOTLOADER;
- dev_vdbg(dev, "%s: bl running\n", __func__);
- if (cd->mode == CY_MODE_BOOTLOADER) {
- /* Signal bootloader heartbeat heard */
- wake_up(&cd->wait_q);
- goto cyttsp4_irq_exit;
- }
-
- /* switch to bootloader */
- dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n",
- __func__, cd->mode, cur_mode);
-
- /* catch operation->bl glitch */
- if (cd->mode != CY_MODE_UNKNOWN) {
- /* Incase startup_state do not let startup_() */
- cd->mode = CY_MODE_UNKNOWN;
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_irq_exit;
- }
-
- /*
- * do not wake thread on this switch since
- * it is possible to get an early heartbeat
- * prior to performing the reset
- */
- cd->mode = cur_mode;
-
- goto cyttsp4_irq_exit;
- }
-
- switch (mode[0] & CY_HST_MODE) {
- case CY_HST_OPERATE:
- cur_mode = CY_MODE_OPERATIONAL;
- dev_vdbg(dev, "%s: operational\n", __func__);
- break;
- case CY_HST_CAT:
- cur_mode = CY_MODE_CAT;
- dev_vdbg(dev, "%s: CaT\n", __func__);
- break;
- case CY_HST_SYSINFO:
- cur_mode = CY_MODE_SYSINFO;
- dev_vdbg(dev, "%s: sysinfo\n", __func__);
- break;
- default:
- cur_mode = CY_MODE_UNKNOWN;
- dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__,
- mode[0]);
- break;
- }
-
- /* Check whether this IRQ should be ignored (internal) */
- if (cd->int_status & CY_INT_IGNORE) {
- dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
- goto cyttsp4_irq_exit;
- }
-
- /* Check for wake up interrupt */
- if (cd->int_status & CY_INT_AWAKE) {
- cd->int_status &= ~CY_INT_AWAKE;
- wake_up(&cd->wait_q);
- dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__);
- goto cyttsp4_irq_handshake;
- }
-
- /* Expecting mode change interrupt */
- if ((cd->int_status & CY_INT_MODE_CHANGE)
- && (mode[0] & CY_HST_MODE_CHANGE) == 0) {
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n",
- __func__, cd->mode, cur_mode);
- cd->mode = cur_mode;
- wake_up(&cd->wait_q);
- goto cyttsp4_irq_handshake;
- }
-
- /* compare current core mode to current device mode */
- dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n",
- __func__, cd->mode, cur_mode);
- if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) {
- /* Unexpected mode change occurred */
- dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode,
- cur_mode, cd->int_status);
- dev_dbg(dev, "%s: Unexpected mode change, startup\n",
- __func__);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_irq_exit;
- }
-
- /* Expecting command complete interrupt */
- dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]);
- if ((cd->int_status & CY_INT_EXEC_CMD)
- && mode[cmd_ofs] & CY_CMD_COMPLETE) {
- cd->int_status &= ~CY_INT_EXEC_CMD;
- dev_vdbg(dev, "%s: Received command complete interrupt\n",
- __func__);
- wake_up(&cd->wait_q);
- /*
- * It is possible to receive a single interrupt for
- * command complete and touch/button status report.
- * Continue processing for a possible status report.
- */
- }
-
- /* This should be status report, read status regs */
- if (cd->mode == CY_MODE_OPERATIONAL) {
- dev_vdbg(dev, "%s: Read status registers\n", __func__);
- rc = cyttsp4_load_status_regs(cd);
- if (rc < 0)
- dev_err(dev, "%s: fail read mode regs r=%d\n",
- __func__, rc);
- }
-
- cyttsp4_mt_attention(cd);
-
-cyttsp4_irq_handshake:
- /* handshake the event */
- dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n",
- __func__, mode[0], rc);
- rc = cyttsp4_handshake(cd, mode[0]);
- if (rc < 0)
- dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n",
- __func__, mode[0], rc);
-
- /*
- * a non-zero udelay period is required for using
- * IRQF_TRIGGER_LOW in order to delay until the
- * device completes isr deassert
- */
- udelay(cd->cpdata->level_irq_udelay);
-
-cyttsp4_irq_exit:
- mutex_unlock(&cd->system_lock);
- return IRQ_HANDLED;
-}
-
-static void cyttsp4_start_wd_timer(struct cyttsp4 *cd)
-{
- if (!CY_WATCHDOG_TIMEOUT)
- return;
-
- mod_timer(&cd->watchdog_timer, jiffies +
- msecs_to_jiffies(CY_WATCHDOG_TIMEOUT));
-}
-
-static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
-{
- if (!CY_WATCHDOG_TIMEOUT)
- return;
-
- /*
- * Ensure we wait until the watchdog timer
- * running on a different CPU finishes
- */
- del_timer_sync(&cd->watchdog_timer);
- cancel_work_sync(&cd->watchdog_work);
- del_timer_sync(&cd->watchdog_timer);
-}
-
-static void cyttsp4_watchdog_timer(struct timer_list *t)
-{
- struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
-
- dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
-
- schedule_work(&cd->watchdog_work);
-
- return;
-}
-
-static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr,
- int timeout_ms)
-{
- int t = msecs_to_jiffies(timeout_ms);
- bool with_timeout = (timeout_ms != 0);
-
- mutex_lock(&cd->system_lock);
- if (!cd->exclusive_dev && cd->exclusive_waits == 0) {
- cd->exclusive_dev = ownptr;
- goto exit;
- }
-
- cd->exclusive_waits++;
-wait:
- mutex_unlock(&cd->system_lock);
- if (with_timeout) {
- t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t);
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting exclusive access\n",
- __func__);
- mutex_lock(&cd->system_lock);
- cd->exclusive_waits--;
- mutex_unlock(&cd->system_lock);
- return -ETIME;
- }
- } else {
- wait_event(cd->wait_q, !cd->exclusive_dev);
- }
- mutex_lock(&cd->system_lock);
- if (cd->exclusive_dev)
- goto wait;
- cd->exclusive_dev = ownptr;
- cd->exclusive_waits--;
-exit:
- mutex_unlock(&cd->system_lock);
-
- return 0;
-}
-
-/*
- * returns error if was not owned
- */
-static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr)
-{
- mutex_lock(&cd->system_lock);
- if (cd->exclusive_dev != ownptr) {
- mutex_unlock(&cd->system_lock);
- return -EINVAL;
- }
-
- dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n",
- __func__, cd->exclusive_dev);
- cd->exclusive_dev = NULL;
- wake_up(&cd->wait_q);
- mutex_unlock(&cd->system_lock);
- return 0;
-}
-
-static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd)
-{
- long t;
- int rc = 0;
-
- /* wait heartbeat */
- dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__);
- t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER,
- msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n",
- __func__, cd->mode);
- rc = -ETIME;
- }
-
- return rc;
-}
-
-static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd)
-{
- long t;
-
- dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__);
-
- t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO,
- msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n",
- __func__, cd->mode);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- mutex_unlock(&cd->system_lock);
- return -ETIME;
- }
-
- return 0;
-}
-
-static int cyttsp4_reset_and_wait(struct cyttsp4 *cd)
-{
- int rc;
-
- /* reset hardware */
- mutex_lock(&cd->system_lock);
- dev_dbg(cd->dev, "%s: reset hw...\n", __func__);
- rc = cyttsp4_hw_reset(cd);
- cd->mode = CY_MODE_UNKNOWN;
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc);
- return rc;
- }
-
- return cyttsp4_wait_bl_heartbeat(cd);
-}
-
-/*
- * returns err if refused or timeout; block until mode change complete
- * bit is set (mode change interrupt)
- */
-static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode)
-{
- u8 new_dev_mode;
- u8 mode;
- long t;
- int rc;
-
- switch (new_mode) {
- case CY_MODE_OPERATIONAL:
- new_dev_mode = CY_HST_OPERATE;
- break;
- case CY_MODE_SYSINFO:
- new_dev_mode = CY_HST_SYSINFO;
- break;
- case CY_MODE_CAT:
- new_dev_mode = CY_HST_CAT;
- break;
- default:
- dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n",
- __func__, new_mode, new_mode);
- return -EINVAL;
- }
-
- /* change mode */
- dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n",
- __func__, "have exclusive", cd->exclusive_dev,
- new_dev_mode, new_mode);
-
- mutex_lock(&cd->system_lock);
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- if (rc < 0) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Fail read mode r=%d\n",
- __func__, rc);
- goto exit;
- }
-
- /* Clear device mode bits and set to new mode */
- mode &= ~CY_HST_MODE;
- mode |= new_dev_mode | CY_HST_MODE_CHANGE;
-
- cd->int_status |= CY_INT_MODE_CHANGE;
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode);
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Fail write mode change r=%d\n",
- __func__, rc);
- goto exit;
- }
-
- /* wait for mode change done interrupt */
- t = wait_event_timeout(cd->wait_q,
- (cd->int_status & CY_INT_MODE_CHANGE) == 0,
- msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
- dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n",
- __func__, t, cd->mode);
-
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: %s\n", __func__,
- "tmo waiting mode change");
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- mutex_unlock(&cd->system_lock);
- rc = -EINVAL;
- }
-
-exit:
- return rc;
-}
-
-static void cyttsp4_watchdog_work(struct work_struct *work)
-{
- struct cyttsp4 *cd =
- container_of(work, struct cyttsp4, watchdog_work);
- u8 *mode;
- int retval;
-
- mutex_lock(&cd->system_lock);
- retval = cyttsp4_load_status_regs(cd);
- if (retval < 0) {
- dev_err(cd->dev,
- "%s: failed to access device in watchdog timer r=%d\n",
- __func__, retval);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_timer_watchdog_exit_error;
- }
- mode = &cd->sysinfo.xy_mode[CY_REG_BASE];
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- dev_err(cd->dev,
- "%s: device found in bootloader mode when operational mode\n",
- __func__);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_timer_watchdog_exit_error;
- }
-
- cyttsp4_start_wd_timer(cd);
-cyttsp4_timer_watchdog_exit_error:
- mutex_unlock(&cd->system_lock);
- return;
-}
-
-static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
-{
- enum cyttsp4_sleep_state ss = SS_SLEEP_ON;
- enum cyttsp4_int_state int_status = CY_INT_IGNORE;
- int rc = 0;
- u8 mode[2];
-
- /* Already in sleep mode? */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_ON) {
- mutex_unlock(&cd->system_lock);
- return 0;
- }
- cd->sleep_state = SS_SLEEPING;
- mutex_unlock(&cd->system_lock);
-
- cyttsp4_stop_wd_timer(cd);
-
- /* Wait until currently running IRQ handler exits and disable IRQ */
- disable_irq(cd->irq);
-
- dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__);
- mutex_lock(&cd->system_lock);
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- if (rc) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
- goto error;
- }
-
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Device in BOOTLOADER mode.\n", __func__);
- rc = -EINVAL;
- goto error;
- }
-
- mode[0] |= CY_HST_SLEEP;
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]);
- mutex_unlock(&cd->system_lock);
- if (rc) {
- dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc);
- goto error;
- }
- dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__);
-
- if (cd->cpdata->power) {
- dev_dbg(cd->dev, "%s: Power down HW\n", __func__);
- rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq);
- } else {
- dev_dbg(cd->dev, "%s: No power function\n", __func__);
- rc = 0;
- }
- if (rc < 0) {
- dev_err(cd->dev, "%s: HW Power down fails r=%d\n",
- __func__, rc);
- goto error;
- }
-
- /* Give time to FW to sleep */
- msleep(50);
-
- goto exit;
-
-error:
- ss = SS_SLEEP_OFF;
- int_status = CY_INT_NONE;
- cyttsp4_start_wd_timer(cd);
-
-exit:
- mutex_lock(&cd->system_lock);
- cd->sleep_state = ss;
- cd->int_status |= int_status;
- mutex_unlock(&cd->system_lock);
- enable_irq(cd->irq);
- return rc;
-}
-
-static int cyttsp4_startup_(struct cyttsp4 *cd)
-{
- int retry = CY_CORE_STARTUP_RETRY_COUNT;
- int rc;
-
- cyttsp4_stop_wd_timer(cd);
-
-reset:
- if (retry != CY_CORE_STARTUP_RETRY_COUNT)
- dev_dbg(cd->dev, "%s: Retry %d\n", __func__,
- CY_CORE_STARTUP_RETRY_COUNT - retry);
-
- /* reset hardware and wait for heartbeat */
- rc = cyttsp4_reset_and_wait(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- /* exit bl into sysinfo mode */
- dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_IGNORE;
- cd->int_status |= CY_INT_MODE_CHANGE;
-
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit),
- (u8 *)ldr_exit);
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- rc = cyttsp4_wait_sysinfo_mode(cd);
- if (rc < 0) {
- u8 buf[sizeof(ldr_err_app)];
- int rc1;
-
- /* Check for invalid/corrupted touch application */
- rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app),
- buf);
- if (rc1) {
- dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1);
- } else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) {
- dev_err(cd->dev, "%s: Error launching touch application\n",
- __func__);
- mutex_lock(&cd->system_lock);
- cd->invalid_touch_app = true;
- mutex_unlock(&cd->system_lock);
- goto exit_no_wd;
- }
-
- if (retry--)
- goto reset;
- goto exit;
- }
-
- mutex_lock(&cd->system_lock);
- cd->invalid_touch_app = false;
- mutex_unlock(&cd->system_lock);
-
- /* read sysinfo data */
- dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__);
- rc = cyttsp4_get_sysinfo_regs(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n",
- __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n",
- __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- cyttsp4_lift_all(&cd->md);
-
- /* restore to sleep if was suspended */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_ON) {
- cd->sleep_state = SS_SLEEP_OFF;
- mutex_unlock(&cd->system_lock);
- cyttsp4_core_sleep_(cd);
- goto exit_no_wd;
- }
- mutex_unlock(&cd->system_lock);
-
-exit:
- cyttsp4_start_wd_timer(cd);
-exit_no_wd:
- return rc;
-}
-
-static int cyttsp4_startup(struct cyttsp4 *cd)
-{
- int rc;
-
- mutex_lock(&cd->system_lock);
- cd->startup_state = STARTUP_RUNNING;
- mutex_unlock(&cd->system_lock);
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- goto exit;
- }
-
- rc = cyttsp4_startup_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- /* Don't return fail code, mode is already changed. */
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
-exit:
- mutex_lock(&cd->system_lock);
- cd->startup_state = STARTUP_NONE;
- mutex_unlock(&cd->system_lock);
-
- /* Wake the waiters for end of startup */
- wake_up(&cd->wait_q);
-
- return rc;
-}
-
-static void cyttsp4_startup_work_function(struct work_struct *work)
-{
- struct cyttsp4 *cd = container_of(work, struct cyttsp4, startup_work);
- int rc;
-
- rc = cyttsp4_startup(cd);
- if (rc < 0)
- dev_err(cd->dev, "%s: Fail queued startup r=%d\n",
- __func__, rc);
-}
-
-static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
-
- if (!si)
- return;
-
- kfree(si->si_ptrs.cydata);
- kfree(si->si_ptrs.test);
- kfree(si->si_ptrs.pcfg);
- kfree(si->si_ptrs.opcfg);
- kfree(si->si_ptrs.ddata);
- kfree(si->si_ptrs.mdata);
- kfree(si->btn);
- kfree(si->xy_mode);
- kfree(si->xy_data);
- kfree(si->btn_rec_data);
-}
-
-#ifdef CONFIG_PM
-static int cyttsp4_core_sleep(struct cyttsp4 *cd)
-{
- int rc;
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- return 0;
- }
-
- rc = cyttsp4_core_sleep_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
- return rc;
-}
-
-static int cyttsp4_core_wake_(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- int rc;
- u8 mode;
- int t;
-
- /* Already woken? */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_OFF) {
- mutex_unlock(&cd->system_lock);
- return 0;
- }
- cd->int_status &= ~CY_INT_IGNORE;
- cd->int_status |= CY_INT_AWAKE;
- cd->sleep_state = SS_WAKING;
-
- if (cd->cpdata->power) {
- dev_dbg(dev, "%s: Power up HW\n", __func__);
- rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
- } else {
- dev_dbg(dev, "%s: No power function\n", __func__);
- rc = -ENOSYS;
- }
- if (rc < 0) {
- dev_err(dev, "%s: HW Power up fails r=%d\n",
- __func__, rc);
-
- /* Initiate a read transaction to wake up */
- cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- } else
- dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
- __func__);
- mutex_unlock(&cd->system_lock);
-
- t = wait_event_timeout(cd->wait_q,
- (cd->int_status & CY_INT_AWAKE) == 0,
- msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_AWAKE;
- /* Try starting up */
- cyttsp4_queue_startup_(cd);
- mutex_unlock(&cd->system_lock);
- }
-
- mutex_lock(&cd->system_lock);
- cd->sleep_state = SS_SLEEP_OFF;
- mutex_unlock(&cd->system_lock);
-
- cyttsp4_start_wd_timer(cd);
-
- return 0;
-}
-
-static int cyttsp4_core_wake(struct cyttsp4 *cd)
-{
- int rc;
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- return 0;
- }
-
- rc = cyttsp4_core_wake_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
- return rc;
-}
-
-static int cyttsp4_core_suspend(struct device *dev)
-{
- struct cyttsp4 *cd = dev_get_drvdata(dev);
- struct cyttsp4_mt_data *md = &cd->md;
- int rc;
-
- md->is_suspended = true;
-
- rc = cyttsp4_core_sleep(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error on sleep\n", __func__);
- return -EAGAIN;
- }
- return 0;
-}
-
-static int cyttsp4_core_resume(struct device *dev)
-{
- struct cyttsp4 *cd = dev_get_drvdata(dev);
- struct cyttsp4_mt_data *md = &cd->md;
- int rc;
-
- md->is_suspended = false;
-
- rc = cyttsp4_core_wake(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error on wake\n", __func__);
- return -EAGAIN;
- }
-
- return 0;
-}
-#endif
-
-const struct dev_pm_ops cyttsp4_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume)
- SET_RUNTIME_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume, NULL)
-};
-EXPORT_SYMBOL_GPL(cyttsp4_pm_ops);
-
-static int cyttsp4_mt_open(struct input_dev *input)
-{
- pm_runtime_get(input->dev.parent);
- return 0;
-}
-
-static void cyttsp4_mt_close(struct input_dev *input)
-{
- struct cyttsp4_mt_data *md = input_get_drvdata(input);
- mutex_lock(&md->report_lock);
- if (!md->is_suspended)
- pm_runtime_put(input->dev.parent);
- mutex_unlock(&md->report_lock);
-}
-
-
-static int cyttsp4_setup_input_device(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- int signal = CY_IGNORE_VALUE;
- int max_x, max_y, max_p, min, max;
- int max_x_tmp, max_y_tmp;
- int i;
- int rc;
-
- dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
- __set_bit(EV_ABS, md->input->evbit);
- __set_bit(EV_REL, md->input->evbit);
- __set_bit(EV_KEY, md->input->evbit);
-
- max_x_tmp = md->si->si_ofs.max_x;
- max_y_tmp = md->si->si_ofs.max_y;
-
- /* get maximum values from the sysinfo data */
- if (md->pdata->flags & CY_FLAG_FLIP) {
- max_x = max_y_tmp - 1;
- max_y = max_x_tmp - 1;
- } else {
- max_x = max_x_tmp - 1;
- max_y = max_y_tmp - 1;
- }
- max_p = md->si->si_ofs.max_p;
-
- /* set event signal capabilities */
- for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
- signal = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST];
- if (signal != CY_IGNORE_VALUE) {
- __set_bit(signal, md->input->absbit);
- min = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_MIN_OST];
- max = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_MAX_OST];
- if (i == CY_ABS_ID_OST) {
- /* shift track ids down to start at 0 */
- max = max - min;
- min = min - min;
- } else if (i == CY_ABS_X_OST)
- max = max_x;
- else if (i == CY_ABS_Y_OST)
- max = max_y;
- else if (i == CY_ABS_P_OST)
- max = max_p;
- input_set_abs_params(md->input, signal, min, max,
- md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST],
- md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]);
- dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
- __func__, signal, min, max);
- if ((i == CY_ABS_ID_OST) &&
- (md->si->si_ofs.tch_rec_size <
- CY_TMA4XX_TCH_REC_SIZE))
- break;
- }
- }
-
- input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max,
- INPUT_MT_DIRECT);
- rc = input_register_device(md->input);
- if (rc < 0)
- dev_err(dev, "%s: Error, failed register input device r=%d\n",
- __func__, rc);
- return rc;
-}
-
-static int cyttsp4_mt_probe(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata;
- int rc = 0;
-
- mutex_init(&md->report_lock);
- md->pdata = pdata;
- /* Create the input device and register it. */
- dev_vdbg(dev, "%s: Create the input device and register it\n",
- __func__);
- md->input = input_allocate_device();
- if (md->input == NULL) {
- dev_err(dev, "%s: Error, failed to allocate input device\n",
- __func__);
- rc = -ENOSYS;
- goto error_alloc_failed;
- }
-
- md->input->name = pdata->inp_dev_name;
- scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev));
- md->input->phys = md->phys;
- md->input->id.bustype = cd->bus_ops->bustype;
- md->input->dev.parent = dev;
- md->input->open = cyttsp4_mt_open;
- md->input->close = cyttsp4_mt_close;
- input_set_drvdata(md->input, md);
-
- /* get sysinfo */
- md->si = &cd->sysinfo;
-
- rc = cyttsp4_setup_input_device(cd);
- if (rc)
- goto error_init_input;
-
- return 0;
-
-error_init_input:
- input_free_device(md->input);
-error_alloc_failed:
- dev_err(dev, "%s failed.\n", __func__);
- return rc;
-}
-
-struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
- struct device *dev, u16 irq, size_t xfer_buf_size)
-{
- struct cyttsp4 *cd;
- struct cyttsp4_platform_data *pdata = dev_get_platdata(dev);
- unsigned long irq_flags;
- int rc = 0;
-
- if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) {
- dev_err(dev, "%s: Missing platform data\n", __func__);
- rc = -ENODEV;
- goto error_no_pdata;
- }
-
- cd = kzalloc(sizeof(*cd), GFP_KERNEL);
- if (!cd) {
- dev_err(dev, "%s: Error, kzalloc\n", __func__);
- rc = -ENOMEM;
- goto error_alloc_data;
- }
-
- cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL);
- if (!cd->xfer_buf) {
- dev_err(dev, "%s: Error, kzalloc\n", __func__);
- rc = -ENOMEM;
- goto error_free_cd;
- }
-
- /* Initialize device info */
- cd->dev = dev;
- cd->pdata = pdata;
- cd->cpdata = pdata->core_pdata;
- cd->bus_ops = ops;
-
- /* Initialize mutexes and spinlocks */
- mutex_init(&cd->system_lock);
- mutex_init(&cd->adap_lock);
-
- /* Initialize wait queue */
- init_waitqueue_head(&cd->wait_q);
-
- /* Initialize works */
- INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function);
- INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work);
-
- /* Initialize IRQ */
- cd->irq = gpio_to_irq(cd->cpdata->irq_gpio);
- if (cd->irq < 0) {
- rc = -EINVAL;
- goto error_free_xfer;
- }
-
- dev_set_drvdata(dev, cd);
-
- /* Call platform init function */
- if (cd->cpdata->init) {
- dev_dbg(cd->dev, "%s: Init HW\n", __func__);
- rc = cd->cpdata->init(cd->cpdata, 1, cd->dev);
- } else {
- dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__);
- rc = 0;
- }
- if (rc < 0)
- dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc);
-
- dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq);
- if (cd->cpdata->level_irq_udelay > 0)
- /* use level triggered interrupts */
- irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
- else
- /* use edge triggered interrupts */
- irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
-
- rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags,
- dev_name(dev), cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error, could not request irq\n", __func__);
- goto error_request_irq;
- }
-
- /* Setup watchdog timer */
- timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
-
- /*
- * call startup directly to ensure that the device
- * is tested before leaving the probe
- */
- rc = cyttsp4_startup(cd);
-
- /* Do not fail probe if startup fails but the device is detected */
- if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) {
- dev_err(cd->dev, "%s: Fail initial startup r=%d\n",
- __func__, rc);
- goto error_startup;
- }
-
- rc = cyttsp4_mt_probe(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error, fail mt probe\n", __func__);
- goto error_startup;
- }
-
- pm_runtime_enable(dev);
-
- return cd;
-
-error_startup:
- cancel_work_sync(&cd->startup_work);
- cyttsp4_stop_wd_timer(cd);
- pm_runtime_disable(dev);
- cyttsp4_free_si_ptrs(cd);
- free_irq(cd->irq, cd);
-error_request_irq:
- if (cd->cpdata->init)
- cd->cpdata->init(cd->cpdata, 0, dev);
-error_free_xfer:
- kfree(cd->xfer_buf);
-error_free_cd:
- kfree(cd);
-error_alloc_data:
-error_no_pdata:
- dev_err(dev, "%s failed.\n", __func__);
- return ERR_PTR(rc);
-}
-EXPORT_SYMBOL_GPL(cyttsp4_probe);
-
-static void cyttsp4_mt_release(struct cyttsp4_mt_data *md)
-{
- input_unregister_device(md->input);
- input_set_drvdata(md->input, NULL);
-}
-
-int cyttsp4_remove(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
-
- cyttsp4_mt_release(&cd->md);
-
- /*
- * Suspend the device before freeing the startup_work and stopping
- * the watchdog since sleep function restarts watchdog on failure
- */
- pm_runtime_suspend(dev);
- pm_runtime_disable(dev);
-
- cancel_work_sync(&cd->startup_work);
-
- cyttsp4_stop_wd_timer(cd);
-
- free_irq(cd->irq, cd);
- if (cd->cpdata->init)
- cd->cpdata->init(cd->cpdata, 0, dev);
- cyttsp4_free_si_ptrs(cd);
- kfree(cd);
- return 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp4_remove);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h
deleted file mode 100644
index 6262f6e45075..000000000000
--- a/drivers/input/touchscreen/cyttsp4_core.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * cyttsp4_core.h
- * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2012 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#ifndef _LINUX_CYTTSP4_CORE_H
-#define _LINUX_CYTTSP4_CORE_H
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/limits.h>
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/platform_data/cyttsp4.h>
-
-#define CY_REG_BASE 0x00
-
-#define CY_POST_CODEL_WDG_RST 0x01
-#define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02
-#define CY_POST_CODEL_PANEL_TEST_FAIL 0x04
-
-#define CY_NUM_BTN_PER_REG 4
-
-/* touch record system information offset masks and shifts */
-#define CY_BYTE_OFS_MASK 0x1F
-#define CY_BOFS_MASK 0xE0
-#define CY_BOFS_SHIFT 5
-
-#define CY_TMA1036_TCH_REC_SIZE 6
-#define CY_TMA4XX_TCH_REC_SIZE 9
-#define CY_TMA1036_MAX_TCH 0x0E
-#define CY_TMA4XX_MAX_TCH 0x1E
-
-#define CY_NORMAL_ORIGIN 0 /* upper, left corner */
-#define CY_INVERT_ORIGIN 1 /* lower, right corner */
-
-/* helpers */
-#define GET_NUM_TOUCHES(x) ((x) & 0x1F)
-#define IS_LARGE_AREA(x) ((x) & 0x20)
-#define IS_BAD_PKT(x) ((x) & 0x20)
-#define IS_BOOTLOADER(hst_mode, reset_detect) \
- ((hst_mode) & 0x01 || (reset_detect) != 0)
-#define IS_TMO(t) ((t) == 0)
-
-
-enum cyttsp_cmd_bits {
- CY_CMD_COMPLETE = (1 << 6),
-};
-
-/* Timeout in ms. */
-#define CY_WATCHDOG_TIMEOUT 1000
-
-#define CY_MAX_PRINT_SIZE 512
-#ifdef VERBOSE_DEBUG
-#define CY_MAX_PRBUF_SIZE PIPE_BUF
-#define CY_PR_TRUNCATED " truncated..."
-#endif
-
-enum cyttsp4_ic_grpnum {
- CY_IC_GRPNUM_RESERVED,
- CY_IC_GRPNUM_CMD_REGS,
- CY_IC_GRPNUM_TCH_REP,
- CY_IC_GRPNUM_DATA_REC,
- CY_IC_GRPNUM_TEST_REC,
- CY_IC_GRPNUM_PCFG_REC,
- CY_IC_GRPNUM_TCH_PARM_VAL,
- CY_IC_GRPNUM_TCH_PARM_SIZE,
- CY_IC_GRPNUM_RESERVED1,
- CY_IC_GRPNUM_RESERVED2,
- CY_IC_GRPNUM_OPCFG_REC,
- CY_IC_GRPNUM_DDATA_REC,
- CY_IC_GRPNUM_MDATA_REC,
- CY_IC_GRPNUM_TEST_REGS,
- CY_IC_GRPNUM_BTN_KEYS,
- CY_IC_GRPNUM_TTHE_REGS,
- CY_IC_GRPNUM_NUM
-};
-
-enum cyttsp4_int_state {
- CY_INT_NONE,
- CY_INT_IGNORE = (1 << 0),
- CY_INT_MODE_CHANGE = (1 << 1),
- CY_INT_EXEC_CMD = (1 << 2),
- CY_INT_AWAKE = (1 << 3),
-};
-
-enum cyttsp4_mode {
- CY_MODE_UNKNOWN,
- CY_MODE_BOOTLOADER = (1 << 1),
- CY_MODE_OPERATIONAL = (1 << 2),
- CY_MODE_SYSINFO = (1 << 3),
- CY_MODE_CAT = (1 << 4),
- CY_MODE_STARTUP = (1 << 5),
- CY_MODE_LOADER = (1 << 6),
- CY_MODE_CHANGE_MODE = (1 << 7),
- CY_MODE_CHANGED = (1 << 8),
- CY_MODE_CMD_COMPLETE = (1 << 9),
-};
-
-enum cyttsp4_sleep_state {
- SS_SLEEP_OFF,
- SS_SLEEP_ON,
- SS_SLEEPING,
- SS_WAKING,
-};
-
-enum cyttsp4_startup_state {
- STARTUP_NONE,
- STARTUP_QUEUED,
- STARTUP_RUNNING,
-};
-
-#define CY_NUM_REVCTRL 8
-struct cyttsp4_cydata {
- u8 ttpidh;
- u8 ttpidl;
- u8 fw_ver_major;
- u8 fw_ver_minor;
- u8 revctrl[CY_NUM_REVCTRL];
- u8 blver_major;
- u8 blver_minor;
- u8 jtag_si_id3;
- u8 jtag_si_id2;
- u8 jtag_si_id1;
- u8 jtag_si_id0;
- u8 mfgid_sz;
- u8 cyito_idh;
- u8 cyito_idl;
- u8 cyito_verh;
- u8 cyito_verl;
- u8 ttsp_ver_major;
- u8 ttsp_ver_minor;
- u8 device_info;
- u8 mfg_id[];
-} __packed;
-
-struct cyttsp4_test {
- u8 post_codeh;
- u8 post_codel;
-} __packed;
-
-struct cyttsp4_pcfg {
- u8 electrodes_x;
- u8 electrodes_y;
- u8 len_xh;
- u8 len_xl;
- u8 len_yh;
- u8 len_yl;
- u8 res_xh;
- u8 res_xl;
- u8 res_yh;
- u8 res_yl;
- u8 max_zh;
- u8 max_zl;
- u8 panel_info0;
-} __packed;
-
-struct cyttsp4_tch_rec_params {
- u8 loc;
- u8 size;
-} __packed;
-
-#define CY_NUM_TCH_FIELDS 7
-#define CY_NUM_EXT_TCH_FIELDS 3
-struct cyttsp4_opcfg {
- u8 cmd_ofs;
- u8 rep_ofs;
- u8 rep_szh;
- u8 rep_szl;
- u8 num_btns;
- u8 tt_stat_ofs;
- u8 obj_cfg0;
- u8 max_tchs;
- u8 tch_rec_size;
- struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS];
- u8 btn_rec_size; /* btn record size (in bytes) */
- u8 btn_diff_ofs; /* btn data loc, diff counts */
- u8 btn_diff_size; /* btn size of diff counts (in bits) */
- struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS];
-} __packed;
-
-struct cyttsp4_sysinfo_ptr {
- struct cyttsp4_cydata *cydata;
- struct cyttsp4_test *test;
- struct cyttsp4_pcfg *pcfg;
- struct cyttsp4_opcfg *opcfg;
- struct cyttsp4_ddata *ddata;
- struct cyttsp4_mdata *mdata;
-} __packed;
-
-struct cyttsp4_sysinfo_data {
- u8 hst_mode;
- u8 reserved;
- u8 map_szh;
- u8 map_szl;
- u8 cydata_ofsh;
- u8 cydata_ofsl;
- u8 test_ofsh;
- u8 test_ofsl;
- u8 pcfg_ofsh;
- u8 pcfg_ofsl;
- u8 opcfg_ofsh;
- u8 opcfg_ofsl;
- u8 ddata_ofsh;
- u8 ddata_ofsl;
- u8 mdata_ofsh;
- u8 mdata_ofsl;
-} __packed;
-
-enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
- CY_TCH_X, /* X */
- CY_TCH_Y, /* Y */
- CY_TCH_P, /* P (Z) */
- CY_TCH_T, /* TOUCH ID */
- CY_TCH_E, /* EVENT ID */
- CY_TCH_O, /* OBJECT ID */
- CY_TCH_W, /* SIZE */
- CY_TCH_MAJ, /* TOUCH_MAJOR */
- CY_TCH_MIN, /* TOUCH_MINOR */
- CY_TCH_OR, /* ORIENTATION */
- CY_TCH_NUM_ABS
-};
-
-struct cyttsp4_touch {
- int abs[CY_TCH_NUM_ABS];
-};
-
-struct cyttsp4_tch_abs_params {
- size_t ofs; /* abs byte offset */
- size_t size; /* size in bits */
- size_t max; /* max value */
- size_t bofs; /* bit offset */
-};
-
-struct cyttsp4_sysinfo_ofs {
- size_t chip_type;
- size_t cmd_ofs;
- size_t rep_ofs;
- size_t rep_sz;
- size_t num_btns;
- size_t num_btn_regs; /* ceil(num_btns/4) */
- size_t tt_stat_ofs;
- size_t tch_rec_size;
- size_t obj_cfg0;
- size_t max_tchs;
- size_t mode_size;
- size_t data_size;
- size_t map_sz;
- size_t max_x;
- size_t x_origin; /* left or right corner */
- size_t max_y;
- size_t y_origin; /* upper or lower corner */
- size_t max_p;
- size_t cydata_ofs;
- size_t test_ofs;
- size_t pcfg_ofs;
- size_t opcfg_ofs;
- size_t ddata_ofs;
- size_t mdata_ofs;
- size_t cydata_size;
- size_t test_size;
- size_t pcfg_size;
- size_t opcfg_size;
- size_t ddata_size;
- size_t mdata_size;
- size_t btn_keys_size;
- struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
- size_t btn_rec_size; /* btn record size (in bytes) */
- size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */
- size_t btn_diff_size;/* btn size of diff counts (in bits) */
-};
-
-enum cyttsp4_btn_state {
- CY_BTN_RELEASED,
- CY_BTN_PRESSED,
- CY_BTN_NUM_STATE
-};
-
-struct cyttsp4_btn {
- bool enabled;
- int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */
- int key_code;
-};
-
-struct cyttsp4_sysinfo {
- bool ready;
- struct cyttsp4_sysinfo_data si_data;
- struct cyttsp4_sysinfo_ptr si_ptrs;
- struct cyttsp4_sysinfo_ofs si_ofs;
- struct cyttsp4_btn *btn; /* button states */
- u8 *btn_rec_data; /* button diff count data */
- u8 *xy_mode; /* operational mode and status regs */
- u8 *xy_data; /* operational touch regs */
-};
-
-struct cyttsp4_mt_data {
- struct cyttsp4_mt_platform_data *pdata;
- struct cyttsp4_sysinfo *si;
- struct input_dev *input;
- struct mutex report_lock;
- bool is_suspended;
- char phys[NAME_MAX];
- int num_prv_tch;
-};
-
-struct cyttsp4 {
- struct device *dev;
- struct mutex system_lock;
- struct mutex adap_lock;
- enum cyttsp4_mode mode;
- enum cyttsp4_sleep_state sleep_state;
- enum cyttsp4_startup_state startup_state;
- int int_status;
- wait_queue_head_t wait_q;
- int irq;
- struct work_struct startup_work;
- struct work_struct watchdog_work;
- struct timer_list watchdog_timer;
- struct cyttsp4_sysinfo sysinfo;
- void *exclusive_dev;
- int exclusive_waits;
- atomic_t ignore_irq;
- bool invalid_touch_app;
- struct cyttsp4_mt_data md;
- struct cyttsp4_platform_data *pdata;
- struct cyttsp4_core_platform_data *cpdata;
- const struct cyttsp4_bus_ops *bus_ops;
- u8 *xfer_buf;
-#ifdef VERBOSE_DEBUG
- u8 pr_buf[CY_MAX_PRBUF_SIZE];
-#endif
-};
-
-struct cyttsp4_bus_ops {
- u16 bustype;
- int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
- const void *values);
- int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
- void *values);
-};
-
-enum cyttsp4_hst_mode_bits {
- CY_HST_TOGGLE = (1 << 7),
- CY_HST_MODE_CHANGE = (1 << 3),
- CY_HST_MODE = (7 << 4),
- CY_HST_OPERATE = (0 << 4),
- CY_HST_SYSINFO = (1 << 4),
- CY_HST_CAT = (2 << 4),
- CY_HST_LOWPOW = (1 << 2),
- CY_HST_SLEEP = (1 << 1),
- CY_HST_RESET = (1 << 0),
-};
-
-/* abs settings */
-#define CY_IGNORE_VALUE 0xFFFF
-
-/* abs signal capabilities offsets in the frameworks array */
-enum cyttsp4_sig_caps {
- CY_SIGNAL_OST,
- CY_MIN_OST,
- CY_MAX_OST,
- CY_FUZZ_OST,
- CY_FLAT_OST,
- CY_NUM_ABS_SET /* number of signal capability fields */
-};
-
-/* abs axis signal offsets in the framworks array */
-enum cyttsp4_sig_ost {
- CY_ABS_X_OST,
- CY_ABS_Y_OST,
- CY_ABS_P_OST,
- CY_ABS_W_OST,
- CY_ABS_ID_OST,
- CY_ABS_MAJ_OST,
- CY_ABS_MIN_OST,
- CY_ABS_OR_OST,
- CY_NUM_ABS_OST /* number of abs signals */
-};
-
-enum cyttsp4_flags {
- CY_FLAG_NONE = 0x00,
- CY_FLAG_HOVER = 0x04,
- CY_FLAG_FLIP = 0x08,
- CY_FLAG_INV_X = 0x10,
- CY_FLAG_INV_Y = 0x20,
- CY_FLAG_VKEYS = 0x40,
-};
-
-enum cyttsp4_object_id {
- CY_OBJ_STANDARD_FINGER,
- CY_OBJ_LARGE_OBJECT,
- CY_OBJ_STYLUS,
- CY_OBJ_HOVER,
-};
-
-enum cyttsp4_event_id {
- CY_EV_NO_EVENT,
- CY_EV_TOUCHDOWN,
- CY_EV_MOVE, /* significant displacement (> act dist) */
- CY_EV_LIFTOFF, /* record reports last position */
-};
-
-/* x-axis resolution of panel in pixels */
-#define CY_PCFG_RESOLUTION_X_MASK 0x7F
-
-/* y-axis resolution of panel in pixels */
-#define CY_PCFG_RESOLUTION_Y_MASK 0x7F
-
-/* x-axis, 0:origin is on left side of panel, 1: right */
-#define CY_PCFG_ORIGIN_X_MASK 0x80
-
-/* y-axis, 0:origin is on top side of panel, 1: bottom */
-#define CY_PCFG_ORIGIN_Y_MASK 0x80
-
-static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u16 addr, int size,
- void *buf)
-{
- return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
-}
-
-static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u16 addr, int size,
- const void *buf)
-{
- return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
-}
-
-extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
- struct device *dev, u16 irq, size_t xfer_buf_size);
-extern int cyttsp4_remove(struct cyttsp4 *ts);
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, void *values);
-extern const struct dev_pm_ops cyttsp4_pm_ops;
-
-#endif /* _LINUX_CYTTSP4_CORE_H */
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c
deleted file mode 100644
index c260bab0c62c..000000000000
--- a/drivers/input/touchscreen/cyttsp4_i2c.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp_i2c.c
- * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- * Copyright (C) 2013 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-
-#include <linux/i2c.h>
-#include <linux/input.h>
-
-#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
-
-static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
- .bustype = BUS_I2C,
- .write = cyttsp_i2c_write_block_data,
- .read = cyttsp_i2c_read_block_data,
-};
-
-static int cyttsp4_i2c_probe(struct i2c_client *client)
-{
- struct cyttsp4 *ts;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "I2C functionality not Supported\n");
- return -EIO;
- }
-
- ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
- CYTTSP4_I2C_DATA_SIZE);
-
- return PTR_ERR_OR_ZERO(ts);
-}
-
-static void cyttsp4_i2c_remove(struct i2c_client *client)
-{
- struct cyttsp4 *ts = i2c_get_clientdata(client);
-
- cyttsp4_remove(ts);
-}
-
-static const struct i2c_device_id cyttsp4_i2c_id[] = {
- { CYTTSP4_I2C_NAME, 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
-
-static struct i2c_driver cyttsp4_i2c_driver = {
- .driver = {
- .name = CYTTSP4_I2C_NAME,
- .pm = &cyttsp4_pm_ops,
- },
- .probe_new = cyttsp4_i2c_probe,
- .remove = cyttsp4_i2c_remove,
- .id_table = cyttsp4_i2c_id,
-};
-
-module_i2c_driver(cyttsp4_i2c_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c
deleted file mode 100644
index 5d7db84f2749..000000000000
--- a/drivers/input/touchscreen/cyttsp4_spi.c
+++ /dev/null
@@ -1,187 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Source for:
- * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- * Copyright (C) 2013 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/spi/spi.h>
-
-#define CY_SPI_WR_OP 0x00 /* r/~w */
-#define CY_SPI_RD_OP 0x01
-#define CY_SPI_BITS_PER_WORD 8
-#define CY_SPI_A8_BIT 0x02
-#define CY_SPI_WR_HEADER_BYTES 2
-#define CY_SPI_RD_HEADER_BYTES 1
-#define CY_SPI_CMD_BYTES 2
-#define CY_SPI_SYNC_BYTE 0
-#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
-#define CY_SPI_DATA_SIZE (2 * 256)
-
-#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
-
-static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
- u8 op, u16 reg, u8 *buf, int length)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct spi_message msg;
- struct spi_transfer xfer[2];
- u8 *wr_buf = &xfer_buf[0];
- u8 rd_buf[CY_SPI_CMD_BYTES];
- int retval;
- int i;
-
- if (length > CY_SPI_DATA_SIZE) {
- dev_err(dev, "%s: length %d is too big.\n",
- __func__, length);
- return -EINVAL;
- }
-
- memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
- memset(rd_buf, 0, CY_SPI_CMD_BYTES);
-
- wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
- if (op == CY_SPI_WR_OP) {
- wr_buf[1] = reg & 0xFF;
- if (length > 0)
- memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
- }
-
- memset(xfer, 0, sizeof(xfer));
- spi_message_init(&msg);
-
- /*
- We set both TX and RX buffers because Cypress TTSP
- requires full duplex operation.
- */
- xfer[0].tx_buf = wr_buf;
- xfer[0].rx_buf = rd_buf;
- switch (op) {
- case CY_SPI_WR_OP:
- xfer[0].len = length + CY_SPI_CMD_BYTES;
- spi_message_add_tail(&xfer[0], &msg);
- break;
-
- case CY_SPI_RD_OP:
- xfer[0].len = CY_SPI_RD_HEADER_BYTES;
- spi_message_add_tail(&xfer[0], &msg);
-
- xfer[1].rx_buf = buf;
- xfer[1].len = length;
- spi_message_add_tail(&xfer[1], &msg);
- break;
-
- default:
- dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
- return -EINVAL;
- }
-
- retval = spi_sync(spi, &msg);
- if (retval < 0) {
- dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
- __func__, retval, xfer[1].len, op);
-
- /*
- * do not return here since was a bad ACK sequence
- * let the following ACK check handle any errors and
- * allow silent retries
- */
- }
-
- if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
- dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
-
- for (i = 0; i < CY_SPI_CMD_BYTES; i++)
- dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
- __func__, i, rd_buf[i]);
- for (i = 0; i < length; i++)
- dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
- __func__, i, buf[i]);
-
- return -EIO;
- }
-
- return 0;
-}
-
-static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, void *data)
-{
- int rc;
-
- rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
- if (rc)
- return rc;
- else
- return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
- length);
-}
-
-static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, const void *data)
-{
- return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
- length);
-}
-
-static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
- .bustype = BUS_SPI,
- .write = cyttsp_spi_write_block_data,
- .read = cyttsp_spi_read_block_data,
-};
-
-static int cyttsp4_spi_probe(struct spi_device *spi)
-{
- struct cyttsp4 *ts;
- int error;
-
- /* Set up SPI*/
- spi->bits_per_word = CY_SPI_BITS_PER_WORD;
- spi->mode = SPI_MODE_0;
- error = spi_setup(spi);
- if (error < 0) {
- dev_err(&spi->dev, "%s: SPI setup error %d\n",
- __func__, error);
- return error;
- }
-
- ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
- CY_SPI_DATA_BUF_SIZE);
-
- return PTR_ERR_OR_ZERO(ts);
-}
-
-static void cyttsp4_spi_remove(struct spi_device *spi)
-{
- struct cyttsp4 *ts = spi_get_drvdata(spi);
- cyttsp4_remove(ts);
-}
-
-static struct spi_driver cyttsp4_spi_driver = {
- .driver = {
- .name = CYTTSP4_SPI_NAME,
- .pm = &cyttsp4_pm_ops,
- },
- .probe = cyttsp4_spi_probe,
- .remove = cyttsp4_spi_remove,
-};
-
-module_spi_driver(cyttsp4_spi_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
-MODULE_AUTHOR("Cypress");
-MODULE_ALIAS("spi:cyttsp4");
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index 4a23d6231382..071b7c9bf566 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -18,10 +18,10 @@
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/regmap.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define CYTTSP5_NAME "cyttsp5"
#define CY_I2C_DATA_SIZE (2 * 256)
@@ -29,7 +29,7 @@
#define CY_MAX_INPUT 512
#define CYTTSP5_PREALLOCATED_CMD_BUFFER 32
#define CY_BITS_PER_BTN 1
-#define CY_NUM_BTN_EVENT_ID GENMASK(CY_BITS_PER_BTN, 0)
+#define CY_NUM_BTN_EVENT_ID GENMASK(CY_BITS_PER_BTN - 1, 0)
#define MAX_AREA 255
#define HID_OUTPUT_BL_SOP 0x1
@@ -43,6 +43,7 @@
#define HID_DESC_REG 0x1
#define HID_INPUT_REG 0x3
#define HID_OUTPUT_REG 0x4
+#define HID_COMMAND_REG 0x5
#define REPORT_ID_TOUCH 0x1
#define REPORT_ID_BTN 0x3
@@ -68,6 +69,7 @@
#define HID_APP_OUTPUT_REPORT_ID 0x2F
#define HID_BL_RESPONSE_REPORT_ID 0x30
#define HID_BL_OUTPUT_REPORT_ID 0x40
+#define HID_RESPONSE_REPORT_ID 0xF0
#define HID_OUTPUT_RESPONSE_REPORT_OFFSET 2
#define HID_OUTPUT_RESPONSE_CMD_OFFSET 4
@@ -78,9 +80,15 @@
#define HID_SYSINFO_BTN_MASK GENMASK(7, 0)
#define HID_SYSINFO_MAX_BTN 8
+#define HID_CMD_SET_POWER 0x8
+
+#define HID_POWER_ON 0x0
+#define HID_POWER_SLEEP 0x1
+
#define CY_HID_OUTPUT_TIMEOUT_MS 200
#define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS 3000
#define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS 4000
+#define CY_HID_SET_POWER_TIMEOUT 500
/* maximum number of concurrent tracks */
#define TOUCH_REPORT_SIZE 10
@@ -100,6 +108,14 @@
#define TOUCH_REPORT_USAGE_PG_MIN 0xFF010063
#define TOUCH_COL_USAGE_PG 0x000D0022
+#define SET_CMD_LOW(byte, bits) \
+ ((byte) = (((byte) & 0xF0) | ((bits) & 0x0F)))
+#define SET_CMD_HIGH(byte, bits)\
+ ((byte) = (((byte) & 0x0F) | ((bits) & 0xF0)))
+#define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode)
+#define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4))
+#define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id)
+
/* System Information interface definitions */
struct cyttsp5_sensing_conf_data_dev {
u8 electrodes_x;
@@ -111,6 +127,7 @@ struct cyttsp5_sensing_conf_data_dev {
__le16 max_z;
u8 origin_x;
u8 origin_y;
+ u8 panel_id;
u8 btn;
u8 scan_mode;
u8 max_num_of_tch_per_refresh_cycle;
@@ -190,7 +207,7 @@ struct cyttsp5 {
int num_prv_rec;
struct regmap *regmap;
struct touchscreen_properties prop;
- struct regulator *vdd;
+ struct regulator_bulk_data supplies[2];
};
/*
@@ -556,10 +573,44 @@ static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts)
return cyttsp5_get_sysinfo_regs(ts);
}
+static int cyttsp5_power_control(struct cyttsp5 *ts, bool on)
+{
+ u8 state = on ? HID_POWER_ON : HID_POWER_SLEEP;
+ u8 cmd[2] = { 0 };
+ int rc;
+
+ SET_CMD_REPORT_TYPE(cmd[0], 0);
+ SET_CMD_REPORT_ID(cmd[0], state);
+ SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
+
+ rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd));
+ if (rc) {
+ dev_err(ts->dev, "Failed to write power command %d", rc);
+ return rc;
+ }
+
+ rc = wait_for_completion_interruptible_timeout(&ts->cmd_done,
+ msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT));
+ if (rc <= 0) {
+ dev_err(ts->dev, "HID power cmd execution timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if (ts->response_buf[2] != HID_RESPONSE_REPORT_ID ||
+ (ts->response_buf[3] & 0x03) != state ||
+ (ts->response_buf[4] & 0x0f) != HID_CMD_SET_POWER) {
+ dev_err(ts->dev, "Validation of the %s response failed\n",
+ on ? "wakeup" : "sleep");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts)
{
int rc;
- u8 cmd[HID_OUTPUT_BL_LAUNCH_APP];
+ u8 cmd[HID_OUTPUT_BL_LAUNCH_APP_SIZE];
u16 crc;
put_unaligned_le16(HID_OUTPUT_BL_LAUNCH_APP_SIZE, cmd);
@@ -600,12 +651,7 @@ static int cyttsp5_get_hid_descriptor(struct cyttsp5 *ts,
struct cyttsp5_hid_desc *desc)
{
struct device *dev = ts->dev;
- __le16 hid_desc_register = cpu_to_le16(HID_DESC_REG);
int rc;
- u8 cmd[2];
-
- /* Set HID descriptor register */
- memcpy(cmd, &hid_desc_register, sizeof(hid_desc_register));
rc = cyttsp5_write(ts, HID_DESC_REG, NULL, 0);
if (rc) {
@@ -674,6 +720,10 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle)
case HID_BTN_REPORT_ID:
cyttsp5_btn_attention(ts->dev);
break;
+ case HID_RESPONSE_REPORT_ID:
+ memcpy(ts->response_buf, ts->input_buf, size);
+ complete(&ts->cmd_done);
+ break;
default:
/* It is not an input but a command response */
memcpy(ts->response_buf, ts->input_buf, size);
@@ -767,7 +817,7 @@ static void cyttsp5_cleanup(void *data)
{
struct cyttsp5 *ts = data;
- regulator_disable(ts->vdd);
+ regulator_bulk_disable(ARRAY_SIZE(ts->supplies), ts->supplies);
}
static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
@@ -790,9 +840,12 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
init_completion(&ts->cmd_done);
/* Power up the device */
- ts->vdd = devm_regulator_get(dev, "vdd");
- if (IS_ERR(ts->vdd)) {
- error = PTR_ERR(ts->vdd);
+ ts->supplies[0].supply = "vdd";
+ ts->supplies[1].supply = "vddio";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->supplies),
+ ts->supplies);
+ if (error) {
+ dev_err(ts->dev, "Failed to get regulators, error %d\n", error);
return error;
}
@@ -800,9 +853,11 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
if (error)
return error;
- error = regulator_enable(ts->vdd);
- if (error)
+ error = regulator_bulk_enable(ARRAY_SIZE(ts->supplies), ts->supplies);
+ if (error) {
+ dev_err(ts->dev, "Failed to enable regulators, error %d\n", error);
return error;
+ }
ts->input = devm_input_allocate_device(dev);
if (!ts->input) {
@@ -815,13 +870,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
ts->input->phys = ts->phys;
input_set_drvdata(ts->input, ts);
- /* Reset the gpio to be in a reset state */
+ /* Assert gpio to be in a reset state */
ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ts->reset_gpio)) {
error = PTR_ERR(ts->reset_gpio);
dev_err(dev, "Failed to request reset gpio, error %d\n", error);
return error;
}
+
+ fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */
+
gpiod_set_value_cansleep(ts->reset_gpio, 0);
/* Need a delay to have device up */
@@ -880,17 +938,40 @@ static const struct of_device_id cyttsp5_of_match[] = {
MODULE_DEVICE_TABLE(of, cyttsp5_of_match);
static const struct i2c_device_id cyttsp5_i2c_id[] = {
- { CYTTSP5_NAME, 0, },
+ { CYTTSP5_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
+static int __maybe_unused cyttsp5_suspend(struct device *dev)
+{
+ struct cyttsp5 *ts = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ cyttsp5_power_control(ts, false);
+
+ return 0;
+}
+
+static int __maybe_unused cyttsp5_resume(struct device *dev)
+{
+ struct cyttsp5 *ts = dev_get_drvdata(dev);
+
+ if (!device_may_wakeup(dev))
+ cyttsp5_power_control(ts, true);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cyttsp5_pm, cyttsp5_suspend, cyttsp5_resume);
+
static struct i2c_driver cyttsp5_i2c_driver = {
.driver = {
.name = CYTTSP5_NAME,
.of_match_table = cyttsp5_of_match,
+ .pm = &cyttsp5_pm,
},
- .probe_new = cyttsp5_i2c_probe,
+ .probe = cyttsp5_i2c_probe,
.id_table = cyttsp5_i2c_id,
};
module_i2c_driver(cyttsp5_i2c_driver);
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 1dbd849c9613..9e729910fbc8 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -14,10 +14,10 @@
*/
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/property.h>
@@ -491,7 +491,7 @@ static int cyttsp_disable(struct cyttsp *ts)
return 0;
}
-static int __maybe_unused cyttsp_suspend(struct device *dev)
+static int cyttsp_suspend(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
int retval = 0;
@@ -509,7 +509,7 @@ static int __maybe_unused cyttsp_suspend(struct device *dev)
return retval;
}
-static int __maybe_unused cyttsp_resume(struct device *dev)
+static int cyttsp_resume(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
@@ -525,8 +525,7 @@ static int __maybe_unused cyttsp_resume(struct device *dev)
return 0;
}
-SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
-EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
static int cyttsp_open(struct input_dev *dev)
{
@@ -616,17 +615,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts)
return 0;
}
-static void cyttsp_disable_regulators(void *_ts)
-{
- struct cyttsp *ts = _ts;
-
- regulator_bulk_disable(ARRAY_SIZE(ts->regulators),
- ts->regulators);
-}
-
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size)
{
+ /*
+ * VCPIN is the analog voltage supply
+ * VDD is the digital voltage supply
+ */
+ static const char * const supplies[] = { "vcpin", "vdd" };
struct cyttsp *ts;
struct input_dev *input_dev;
int error;
@@ -644,29 +640,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
ts->bus_ops = bus_ops;
ts->irq = irq;
- /*
- * VCPIN is the analog voltage supply
- * VDD is the digital voltage supply
- */
- ts->regulators[0].supply = "vcpin";
- ts->regulators[1].supply = "vdd";
- error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
- ts->regulators);
- if (error) {
- dev_err(dev, "Failed to get regulators: %d\n", error);
- return ERR_PTR(error);
- }
-
- error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators),
- ts->regulators);
- if (error) {
- dev_err(dev, "Cannot enable regulators: %d\n", error);
- return ERR_PTR(error);
- }
-
- error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts);
+ error = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies),
+ supplies);
if (error) {
- dev_err(dev, "failed to install chip disable handler\n");
+ dev_err(dev, "Failed to enable regulators: %d\n", error);
return ERR_PTR(error);
}
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index 075509e695a2..40a605d20285 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -122,7 +122,6 @@ struct cyttsp {
enum cyttsp_state state;
bool suspended;
- struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio;
bool use_hndshk;
u8 act_dist;
@@ -137,10 +136,6 @@ struct cyttsp {
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size);
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index 0155a1626adf..cb15600549cd 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -22,6 +22,61 @@
#define CY_I2C_DATA_SIZE 128
+static int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
+ u16 addr, u8 length, void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+ u8 addr_lo = addr & 0xFF;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &addr_lo,
+ },
+ {
+ .addr = client_addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = values,
+ },
+ };
+ int retval;
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
+static int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
+ u16 addr, u8 length, const void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+ u8 addr_lo = addr & 0xFF;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client_addr,
+ .flags = 0,
+ .len = length + 1,
+ .buf = xfer_buf,
+ },
+ };
+ int retval;
+
+ xfer_buf[0] = addr_lo;
+ memcpy(&xfer_buf[1], values, length);
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
@@ -48,7 +103,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id cyttsp_i2c_id[] = {
- { CY_I2C_NAME, 0 },
+ { CY_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
@@ -63,10 +118,10 @@ MODULE_DEVICE_TABLE(of, cyttsp_of_i2c_match);
static struct i2c_driver cyttsp_i2c_driver = {
.driver = {
.name = CY_I2C_NAME,
- .pm = &cyttsp_pm_ops,
+ .pm = pm_sleep_ptr(&cyttsp_pm_ops),
.of_match_table = cyttsp_of_i2c_match,
},
- .probe_new = cyttsp_i2c_probe,
+ .probe = cyttsp_i2c_probe,
.id_table = cyttsp_i2c_id,
};
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c
deleted file mode 100644
index 1f0b6d6f48e2..000000000000
--- a/drivers/input/touchscreen/cyttsp_i2c_common.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp_i2c_common.c
- * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
- * For use with Cypress Txx3xx and Txx4xx parts.
- * Supported parts include:
- * CY8CTST341
- * CY8CTMA340
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include "cyttsp4_core.h"
-
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, void *values)
-{
- struct i2c_client *client = to_i2c_client(dev);
- u8 client_addr = client->addr | ((addr >> 8) & 0x1);
- u8 addr_lo = addr & 0xFF;
- struct i2c_msg msgs[] = {
- {
- .addr = client_addr,
- .flags = 0,
- .len = 1,
- .buf = &addr_lo,
- },
- {
- .addr = client_addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = values,
- },
- };
- int retval;
-
- retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (retval < 0)
- return retval;
-
- return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
-
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, const void *values)
-{
- struct i2c_client *client = to_i2c_client(dev);
- u8 client_addr = client->addr | ((addr >> 8) & 0x1);
- u8 addr_lo = addr & 0xFF;
- struct i2c_msg msgs[] = {
- {
- .addr = client_addr,
- .flags = 0,
- .len = length + 1,
- .buf = xfer_buf,
- },
- };
- int retval;
-
- xfer_buf[0] = addr_lo;
- memcpy(&xfer_buf[1], values, length);
-
- retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (retval < 0)
- return retval;
-
- return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 30c6fbf86a86..ada17f2dadf3 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, cyttsp_of_spi_match);
static struct spi_driver cyttsp_spi_driver = {
.driver = {
.name = CY_SPI_NAME,
- .pm = &cyttsp_pm_ops,
+ .pm = pm_sleep_ptr(&cyttsp_pm_ops),
.of_match_table = cyttsp_of_spi_match,
},
.probe = cyttsp_spi_probe,
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
index f91d0e02ddae..c2d3252f8466 100644
--- a/drivers/input/touchscreen/da9052_tsi.c
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -232,7 +232,7 @@ static int da9052_ts_probe(struct platform_device *pdev)
if (!da9052)
return -EINVAL;
- tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
+ tsi = kzalloc(sizeof(*tsi), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tsi || !input_dev) {
error = -ENOMEM;
@@ -311,7 +311,7 @@ err_free_mem:
return error;
}
-static int da9052_ts_remove(struct platform_device *pdev)
+static void da9052_ts_remove(struct platform_device *pdev)
{
struct da9052_tsi *tsi = platform_get_drvdata(pdev);
@@ -322,8 +322,6 @@ static int da9052_ts_remove(struct platform_device *pdev)
input_unregister_device(tsi->dev);
kfree(tsi);
-
- return 0;
}
static struct platform_driver da9052_tsi_driver = {
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index dc07fca7c5ed..fe626a226b85 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -110,7 +110,7 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
+ pdynapro = kzalloc(sizeof(*pdynapro), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pdynapro || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index ddd0f1f62458..bf498bd4dea9 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -3,6 +3,7 @@
* Copyright (C) 2012 Simon Budig, <simon.budig@kernelconcepts.de>
* Daniel Wagener <daniel.wagener@kernelconcepts.de> (M09 firmware support)
* Lothar Waßmann <LW@KARO-electronics.de> (DT support)
+ * Dario Binacchi <dario.binacchi@amarulasolutions.com> (regmap support)
*/
/*
@@ -26,11 +27,12 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/ratelimit.h>
+#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define WORK_REGISTER_THRESHOLD 0x00
#define WORK_REGISTER_REPORT_RATE 0x08
@@ -75,6 +77,9 @@
#define EDT_DEFAULT_NUM_X 1024
#define EDT_DEFAULT_NUM_Y 1024
+#define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc)
+#define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f)
+
enum edt_pmode {
EDT_PMODE_NOT_SUPPORTED,
EDT_PMODE_HIBERNATE,
@@ -112,8 +117,9 @@ struct edt_ft5x06_ts_data {
struct gpio_desc *reset_gpio;
struct gpio_desc *wake_gpio;
+ struct regmap *regmap;
+
#if defined(CONFIG_DEBUG_FS)
- struct dentry *debug_dir;
u8 *raw_buffer;
size_t raw_bufsize;
#endif
@@ -128,6 +134,10 @@ struct edt_ft5x06_ts_data {
int offset_y;
int report_rate;
int max_support_points;
+ int point_len;
+ u8 tdata_cmd;
+ int tdata_len;
+ int tdata_offset;
char name[EDT_NAME_LEN];
char fw_version[EDT_NAME_LEN];
@@ -142,37 +152,10 @@ struct edt_i2c_chip_data {
int max_support_points;
};
-static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
- u16 wr_len, u8 *wr_buf,
- u16 rd_len, u8 *rd_buf)
-{
- struct i2c_msg wrmsg[2];
- int i = 0;
- int ret;
-
- if (wr_len) {
- wrmsg[i].addr = client->addr;
- wrmsg[i].flags = 0;
- wrmsg[i].len = wr_len;
- wrmsg[i].buf = wr_buf;
- i++;
- }
- if (rd_len) {
- wrmsg[i].addr = client->addr;
- wrmsg[i].flags = I2C_M_RD;
- wrmsg[i].len = rd_len;
- wrmsg[i].buf = rd_buf;
- i++;
- }
-
- ret = i2c_transfer(client->adapter, wrmsg, i);
- if (ret < 0)
- return ret;
- if (ret != i)
- return -EIO;
-
- return 0;
-}
+static const struct regmap_config edt_ft5x06_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
u8 *buf, int buflen)
@@ -183,78 +166,154 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
for (i = 0; i < buflen - 1; i++)
crc ^= buf[i];
- if (crc != buf[buflen-1]) {
+ if (crc != buf[buflen - 1]) {
tsdata->crc_errors++;
dev_err_ratelimited(&tsdata->client->dev,
"crc error: 0x%02x expected, got 0x%02x\n",
- crc, buf[buflen-1]);
+ crc, buf[buflen - 1]);
return false;
}
return true;
}
-static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size,
+ void *val_buf, size_t val_size)
{
- struct edt_ft5x06_ts_data *tsdata = dev_id;
- struct device *dev = &tsdata->client->dev;
- u8 cmd;
- u8 rdbuf[63];
- int i, type, x, y, id;
- int offset, tplen, datalen, crclen;
- int error;
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c);
+ struct i2c_msg xfer[2];
+ bool reg_read = false;
+ u8 addr;
+ u8 wlen;
+ u8 wbuf[4], rbuf[3];
+ int ret;
- switch (tsdata->version) {
- case EDT_M06:
- cmd = 0xf9; /* tell the controller to send touch data */
- offset = 5; /* where the actual touch data starts */
- tplen = 4; /* data comes in so called frames */
- crclen = 1; /* length of the crc data */
+ addr = *((u8 *)reg_buf);
+ wbuf[0] = addr;
+ switch (addr) {
+ case 0xf5:
+ wlen = 3;
+ wbuf[0] = 0xf5;
+ wbuf[1] = 0xe;
+ wbuf[2] = *((u8 *)val_buf);
break;
-
- case EDT_M09:
- case EDT_M12:
- case EV_FT:
- case GENERIC_FT:
- cmd = 0x0;
- offset = 3;
- tplen = 6;
- crclen = 0;
+ case 0xf9:
+ wlen = 1;
break;
-
default:
- goto out;
+ wlen = 2;
+ reg_read = true;
+ wbuf[0] = M06_REG_CMD(tsdata->factory_mode);
+ wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr);
+ wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
}
- memset(rdbuf, 0, sizeof(rdbuf));
- datalen = tplen * tsdata->max_support_points + offset + crclen;
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = wlen;
+ xfer[0].buf = wbuf;
- error = edt_ft5x06_ts_readwrite(tsdata->client,
- sizeof(cmd), &cmd,
- datalen, rdbuf);
- if (error) {
- dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
- error);
- goto out;
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = reg_read ? 2 : val_size;
+ xfer[1].buf = reg_read ? rbuf : val_buf;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret != 2) {
+ if (ret < 0)
+ return ret;
+
+ return -EIO;
}
- /* M09/M12 does not send header or CRC */
- if (tsdata->version == EDT_M06) {
- if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
- rdbuf[2] != datalen) {
+ if (addr == 0xf9) {
+ u8 *buf = (u8 *)val_buf;
+
+ if (buf[0] != 0xaa || buf[1] != 0xaa ||
+ buf[2] != val_size) {
tsdata->header_errors++;
dev_err_ratelimited(dev,
- "Unexpected header: %02x%02x%02x!\n",
- rdbuf[0], rdbuf[1], rdbuf[2]);
- goto out;
+ "Unexpected header: %02x%02x%02x\n",
+ buf[0], buf[1], buf[2]);
+ return -EIO;
}
- if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen))
- goto out;
+ if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size))
+ return -EIO;
+ } else if (reg_read) {
+ wbuf[2] = rbuf[0];
+ wbuf[3] = rbuf[1];
+ if (!edt_ft5x06_ts_check_crc(tsdata, wbuf, 4))
+ return -EIO;
+
+ *((u8 *)val_buf) = rbuf[0];
+ }
+
+ return 0;
+}
+
+static int edt_M06_i2c_write(void *context, const void *data, size_t count)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c);
+ u8 addr, val;
+ u8 wbuf[4];
+ struct i2c_msg xfer;
+ int ret;
+
+ addr = *((u8 *)data);
+ val = *((u8 *)data + 1);
+
+ wbuf[0] = M06_REG_CMD(tsdata->factory_mode);
+ wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr);
+ wbuf[2] = val;
+ wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2];
+
+ xfer.addr = i2c->addr;
+ xfer.flags = 0;
+ xfer.len = 4;
+ xfer.buf = wbuf;
+
+ ret = i2c_transfer(i2c->adapter, &xfer, 1);
+ if (ret != 1) {
+ if (ret < 0)
+ return ret;
+
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config edt_M06_i2c_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read = edt_M06_i2c_read,
+ .write = edt_M06_i2c_write,
+};
+
+static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
+{
+ struct edt_ft5x06_ts_data *tsdata = dev_id;
+ struct device *dev = &tsdata->client->dev;
+ u8 rdbuf[63];
+ int i, type, x, y, id;
+ int error;
+
+ memset(rdbuf, 0, sizeof(rdbuf));
+ error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf,
+ tsdata->tdata_len);
+ if (error) {
+ dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n",
+ error);
+ goto out;
}
for (i = 0; i < tsdata->max_support_points; i++) {
- u8 *buf = &rdbuf[i * tplen + offset];
+ u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset];
type = buf[0] >> 6;
/* ignore Reserved events */
@@ -287,79 +346,6 @@ out:
return IRQ_HANDLED;
}
-static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
- u8 addr, u8 value)
-{
- u8 wrbuf[4];
-
- switch (tsdata->version) {
- case EDT_M06:
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[2] = value;
- wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
- return edt_ft5x06_ts_readwrite(tsdata->client, 4,
- wrbuf, 0, NULL);
-
- case EDT_M09:
- case EDT_M12:
- case EV_FT:
- case GENERIC_FT:
- wrbuf[0] = addr;
- wrbuf[1] = value;
-
- return edt_ft5x06_ts_readwrite(tsdata->client, 2,
- wrbuf, 0, NULL);
-
- default:
- return -EINVAL;
- }
-}
-
-static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
- u8 addr)
-{
- u8 wrbuf[2], rdbuf[2];
- int error;
-
- switch (tsdata->version) {
- case EDT_M06:
- wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
- wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
- wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
-
- error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2,
- rdbuf);
- if (error)
- return error;
-
- if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) {
- dev_err(&tsdata->client->dev,
- "crc error: 0x%02x expected, got 0x%02x\n",
- wrbuf[0] ^ wrbuf[1] ^ rdbuf[0],
- rdbuf[1]);
- return -EIO;
- }
- break;
-
- case EDT_M09:
- case EDT_M12:
- case EV_FT:
- case GENERIC_FT:
- wrbuf[0] = addr;
- error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
- wrbuf, 1, rdbuf);
- if (error)
- return error;
- break;
-
- default:
- return -EINVAL;
- }
-
- return rdbuf[0];
-}
-
struct edt_ft5x06_attribute {
struct device_attribute dattr;
size_t field_offset;
@@ -393,7 +379,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
struct edt_ft5x06_attribute *attr =
container_of(dattr, struct edt_ft5x06_attribute, dattr);
u8 *field = (u8 *)tsdata + attr->field_offset;
- int val;
+ unsigned int val;
size_t count = 0;
int error = 0;
u8 addr;
@@ -426,9 +412,8 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
}
if (addr != NO_REGISTER) {
- val = edt_ft5x06_register_read(tsdata, addr);
- if (val < 0) {
- error = val;
+ error = regmap_read(tsdata->regmap, addr, &val);
+ if (error) {
dev_err(&tsdata->client->dev,
"Failed to fetch attribute %s, error %d\n",
dattr->attr.name, error);
@@ -445,7 +430,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
*field = val;
}
- count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
+ count = sysfs_emit(buf, "%d\n", val);
out:
mutex_unlock(&tsdata->mutex);
return error ?: count;
@@ -501,7 +486,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
}
if (addr != NO_REGISTER) {
- error = edt_ft5x06_register_write(tsdata, addr, val);
+ error = regmap_write(tsdata->regmap, addr, val);
if (error) {
dev_err(&tsdata->client->dev,
"Failed to update attribute %s, error: %d\n",
@@ -594,32 +579,24 @@ static struct attribute *edt_ft5x06_attrs[] = {
&dev_attr_crc_errors.attr,
NULL
};
-
-static const struct attribute_group edt_ft5x06_attr_group = {
- .attrs = edt_ft5x06_attrs,
-};
+ATTRIBUTE_GROUPS(edt_ft5x06);
static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+ struct regmap *regmap = tsdata->regmap;
- edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold,
- tsdata->threshold);
- edt_ft5x06_register_write(tsdata, reg_addr->reg_gain,
- tsdata->gain);
+ regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold);
+ regmap_write(regmap, reg_addr->reg_gain, tsdata->gain);
if (reg_addr->reg_offset != NO_REGISTER)
- edt_ft5x06_register_write(tsdata, reg_addr->reg_offset,
- tsdata->offset);
+ regmap_write(regmap, reg_addr->reg_offset, tsdata->offset);
if (reg_addr->reg_offset_x != NO_REGISTER)
- edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x,
- tsdata->offset_x);
+ regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x);
if (reg_addr->reg_offset_y != NO_REGISTER)
- edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y,
- tsdata->offset_y);
+ regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
- edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate,
- tsdata->report_rate);
-
+ regmap_write(regmap, reg_addr->reg_report_rate,
+ tsdata->report_rate);
}
#ifdef CONFIG_DEBUG_FS
@@ -627,7 +604,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
{
struct i2c_client *client = tsdata->client;
int retries = EDT_SWITCH_MODE_RETRIES;
- int ret;
+ unsigned int val;
int error;
if (tsdata->version != EDT_M06) {
@@ -649,7 +626,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
}
/* mode register is 0x3c when in the work mode */
- error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
+ error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03);
if (error) {
dev_err(&client->dev,
"failed to switch to factory mode, error %d\n", error);
@@ -660,8 +637,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
do {
mdelay(EDT_SWITCH_MODE_DELAY);
/* mode register is 0x01 when in factory mode */
- ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE);
- if (ret == 0x03)
+ error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE,
+ &val);
+ if (!error && val == 0x03)
break;
} while (--retries > 0);
@@ -687,11 +665,11 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
{
struct i2c_client *client = tsdata->client;
int retries = EDT_SWITCH_MODE_RETRIES;
- int ret;
+ unsigned int val;
int error;
/* mode register is 0x01 when in the factory mode */
- error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1);
+ error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1);
if (error) {
dev_err(&client->dev,
"failed to switch to work mode, error: %d\n", error);
@@ -703,8 +681,8 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
do {
mdelay(EDT_SWITCH_MODE_DELAY);
/* mode register is 0x01 when in factory mode */
- ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE);
- if (ret == 0x01)
+ error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val);
+ if (!error && val == 0x01)
break;
} while (--retries > 0);
@@ -757,15 +735,16 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
edt_ft5x06_debugfs_mode_set, "%llu\n");
static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
- char __user *buf, size_t count, loff_t *off)
+ char __user *buf, size_t count,
+ loff_t *off)
{
struct edt_ft5x06_ts_data *tsdata = file->private_data;
struct i2c_client *client = tsdata->client;
int retries = EDT_RAW_DATA_RETRIES;
- int val, i, error;
+ unsigned int val;
+ int i, error;
size_t read = 0;
int colbytes;
- char wrbuf[3];
u8 *rdbuf;
if (*off < 0 || *off >= tsdata->raw_bufsize)
@@ -778,29 +757,29 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
goto out;
}
- error = edt_ft5x06_register_write(tsdata, 0x08, 0x01);
+ error = regmap_write(tsdata->regmap, 0x08, 0x01);
if (error) {
- dev_dbg(&client->dev,
+ dev_err(&client->dev,
"failed to write 0x08 register, error %d\n", error);
goto out;
}
do {
usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100);
- val = edt_ft5x06_register_read(tsdata, 0x08);
- if (val < 1)
+ error = regmap_read(tsdata->regmap, 0x08, &val);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to read 0x08 register, error %d\n",
+ error);
+ goto out;
+ }
+
+ if (val == 1)
break;
} while (--retries > 0);
- if (val < 0) {
- error = val;
- dev_dbg(&client->dev,
- "failed to read 0x08 register, error %d\n", error);
- goto out;
- }
-
if (retries == 0) {
- dev_dbg(&client->dev,
+ dev_err(&client->dev,
"timed out waiting for register to settle\n");
error = -ETIMEDOUT;
goto out;
@@ -809,13 +788,9 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
rdbuf = tsdata->raw_buffer;
colbytes = tsdata->num_y * sizeof(u16);
- wrbuf[0] = 0xf5;
- wrbuf[1] = 0x0e;
for (i = 0; i < tsdata->num_x; i++) {
- wrbuf[2] = i; /* column index */
- error = edt_ft5x06_ts_readwrite(tsdata->client,
- sizeof(wrbuf), wrbuf,
- colbytes, rdbuf);
+ rdbuf[0] = i; /* column index */
+ error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes);
if (error)
goto out;
@@ -839,23 +814,21 @@ static const struct file_operations debugfs_raw_data_fops = {
.read = edt_ft5x06_debugfs_raw_data_read,
};
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+ struct dentry *debug_dir = tsdata->client->debugfs;
- debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
- debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
+ debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x);
+ debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y);
debugfs_create_file("mode", S_IRUSR | S_IWUSR,
- tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+ debug_dir, tsdata, &debugfs_mode_fops);
debugfs_create_file("raw_data", S_IRUSR,
- tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
+ debug_dir, tsdata, &debugfs_raw_data_fops);
}
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- debugfs_remove_recursive(tsdata->debug_dir);
kfree(tsdata->raw_buffer);
}
@@ -866,8 +839,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
return -ENOSYS;
}
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
}
@@ -891,8 +863,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
* to have garbage in there
*/
memset(rdbuf, 0, sizeof(rdbuf));
- error = edt_ft5x06_ts_readwrite(client, 1, "\xBB",
- EDT_NAME_LEN - 1, rdbuf);
+ error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1);
if (error)
return error;
@@ -914,6 +885,14 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
*p++ = '\0';
strscpy(model_name, rdbuf + 1, EDT_NAME_LEN);
strscpy(fw_version, p ? p : "", EDT_NAME_LEN);
+
+ regmap_exit(tsdata->regmap);
+ tsdata->regmap = regmap_init_i2c(client,
+ &edt_M06_i2c_regmap_config);
+ if (IS_ERR(tsdata->regmap)) {
+ dev_err(&client->dev, "regmap allocation failed\n");
+ return PTR_ERR(tsdata->regmap);
+ }
} else if (!strncasecmp(rdbuf, "EP0", 3)) {
tsdata->version = EDT_M12;
@@ -931,7 +910,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
} else {
/* If it is not an EDT M06/M12 touchscreen, then the model
* detection is a bit hairy. The different ft5x06
- * firmares around don't reliably implement the
+ * firmwares around don't reliably implement the
* identification registers. Well, we'll take a shot.
*
* The main difference between generic focaltec based
@@ -940,15 +919,13 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
*/
tsdata->version = GENERIC_FT;
- error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
- 2, rdbuf);
+ error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2);
if (error)
return error;
strscpy(fw_version, rdbuf, 2);
- error = edt_ft5x06_ts_readwrite(client, 1, "\xA8",
- 1, rdbuf);
+ error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1);
if (error)
return error;
@@ -965,20 +942,19 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
case 0x70: /* EDT EP0700M09 */
tsdata->version = EDT_M09;
snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
- rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+ rdbuf[0] >> 4, rdbuf[0] & 0x0F);
break;
case 0xa1: /* EDT EP1010ML00 */
tsdata->version = EDT_M09;
snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
- rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+ rdbuf[0] >> 4, rdbuf[0] & 0x0F);
break;
case 0x5a: /* Solomon Goldentek Display */
snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
break;
case 0x59: /* Evervision Display with FT5xx6 TS */
tsdata->version = EV_FT;
- error = edt_ft5x06_ts_readwrite(client, 1, "\x53",
- 1, rdbuf);
+ error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1);
if (error)
return error;
strscpy(fw_version, rdbuf, 1);
@@ -1000,42 +976,40 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+ struct regmap *regmap = tsdata->regmap;
u32 val;
int error;
error = device_property_read_u32(dev, "threshold", &val);
if (!error) {
- edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val);
+ regmap_write(regmap, reg_addr->reg_threshold, val);
tsdata->threshold = val;
}
error = device_property_read_u32(dev, "gain", &val);
if (!error) {
- edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val);
+ regmap_write(regmap, reg_addr->reg_gain, val);
tsdata->gain = val;
}
error = device_property_read_u32(dev, "offset", &val);
if (!error) {
if (reg_addr->reg_offset != NO_REGISTER)
- edt_ft5x06_register_write(tsdata,
- reg_addr->reg_offset, val);
+ regmap_write(regmap, reg_addr->reg_offset, val);
tsdata->offset = val;
}
error = device_property_read_u32(dev, "offset-x", &val);
if (!error) {
if (reg_addr->reg_offset_x != NO_REGISTER)
- edt_ft5x06_register_write(tsdata,
- reg_addr->reg_offset_x, val);
+ regmap_write(regmap, reg_addr->reg_offset_x, val);
tsdata->offset_x = val;
}
error = device_property_read_u32(dev, "offset-y", &val);
if (!error) {
if (reg_addr->reg_offset_y != NO_REGISTER)
- edt_ft5x06_register_write(tsdata,
- reg_addr->reg_offset_y, val);
+ regmap_write(regmap, reg_addr->reg_offset_y, val);
tsdata->offset_y = val;
}
}
@@ -1043,30 +1017,50 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev,
static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
{
struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+ struct regmap *regmap = tsdata->regmap;
+ unsigned int val;
- tsdata->threshold = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_threshold);
- tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain);
+ regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold);
+ regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain);
if (reg_addr->reg_offset != NO_REGISTER)
- tsdata->offset =
- edt_ft5x06_register_read(tsdata, reg_addr->reg_offset);
+ regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset);
if (reg_addr->reg_offset_x != NO_REGISTER)
- tsdata->offset_x = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_offset_x);
+ regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x);
if (reg_addr->reg_offset_y != NO_REGISTER)
- tsdata->offset_y = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_offset_y);
+ regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y);
if (reg_addr->reg_report_rate != NO_REGISTER)
- tsdata->report_rate = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_report_rate);
+ regmap_read(regmap, reg_addr->reg_report_rate,
+ &tsdata->report_rate);
tsdata->num_x = EDT_DEFAULT_NUM_X;
- if (reg_addr->reg_num_x != NO_REGISTER)
- tsdata->num_x = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_num_x);
+ if (reg_addr->reg_num_x != NO_REGISTER) {
+ if (!regmap_read(regmap, reg_addr->reg_num_x, &val))
+ tsdata->num_x = val;
+ }
tsdata->num_y = EDT_DEFAULT_NUM_Y;
- if (reg_addr->reg_num_y != NO_REGISTER)
- tsdata->num_y = edt_ft5x06_register_read(tsdata,
- reg_addr->reg_num_y);
+ if (reg_addr->reg_num_y != NO_REGISTER) {
+ if (!regmap_read(regmap, reg_addr->reg_num_y, &val))
+ tsdata->num_y = val;
+ }
+}
+
+static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata)
+{
+ int crclen;
+
+ if (tsdata->version == EDT_M06) {
+ tsdata->tdata_cmd = 0xf9;
+ tsdata->tdata_offset = 5;
+ tsdata->point_len = 4;
+ crclen = 1;
+ } else {
+ tsdata->tdata_cmd = 0x0;
+ tsdata->tdata_offset = 3;
+ tsdata->point_len = 6;
+ crclen = 0;
+ }
+
+ tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points +
+ tsdata->tdata_offset + crclen;
}
static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
@@ -1123,6 +1117,14 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
}
}
+static void edt_ft5x06_exit_regmap(void *arg)
+{
+ struct edt_ft5x06_ts_data *data = arg;
+
+ if (!IS_ERR_OR_NULL(data->regmap))
+ regmap_exit(data->regmap);
+}
+
static void edt_ft5x06_disable_regulators(void *arg)
{
struct edt_ft5x06_ts_data *data = arg;
@@ -1136,7 +1138,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct edt_i2c_chip_data *chip_data;
struct edt_ft5x06_ts_data *tsdata;
- u8 buf[2] = { 0xfc, 0x00 };
+ unsigned int val;
struct input_dev *input;
unsigned long irq_flags;
int error;
@@ -1150,6 +1152,22 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
return -ENOMEM;
}
+ tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config);
+ if (IS_ERR(tsdata->regmap)) {
+ dev_err(&client->dev, "regmap allocation failed\n");
+ return PTR_ERR(tsdata->regmap);
+ }
+
+ /*
+ * We are not using devm_regmap_init_i2c() and instead install a
+ * custom action because we may replace regmap with M06-specific one
+ * and we need to make sure that it will not be released too early.
+ */
+ error = devm_add_action_or_reset(&client->dev, edt_ft5x06_exit_regmap,
+ tsdata);
+ if (error)
+ return error;
+
chip_data = device_get_match_data(&client->dev);
if (!chip_data)
chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
@@ -1161,13 +1179,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
tsdata->max_support_points = chip_data->max_support_points;
tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
- if (IS_ERR(tsdata->vcc)) {
- error = PTR_ERR(tsdata->vcc);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "failed to request regulator: %d\n", error);
- return error;
- }
+ if (IS_ERR(tsdata->vcc))
+ return dev_err_probe(&client->dev, PTR_ERR(tsdata->vcc),
+ "failed to request regulator\n");
tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
if (IS_ERR(tsdata->iovcc)) {
@@ -1219,7 +1233,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
}
/*
- * Check which sleep modes we can support. Power-off requieres the
+ * Check which sleep modes we can support. Power-off requires the
* reset-pin to ensure correct power-down/power-up behaviour. Start with
* the EDT_PMODE_POWEROFF test since this is the deepest possible sleep
* mode.
@@ -1234,6 +1248,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (tsdata->wake_gpio) {
usleep_range(5000, 6000);
gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
+ usleep_range(5000, 6000);
}
if (tsdata->reset_gpio) {
@@ -1252,6 +1267,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
tsdata->client = client;
tsdata->input = input;
tsdata->factory_mode = false;
+ i2c_set_clientdata(client, tsdata);
error = edt_ft5x06_ts_identify(client, tsdata);
if (error) {
@@ -1263,8 +1279,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
* Dummy read access. EP0700MLP1 returns bogus data on the first
* register read access and ignores writes.
*/
- edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf);
+ regmap_read(tsdata->regmap, 0x00, &val);
+ edt_ft5x06_ts_set_tdata_parameters(tsdata);
edt_ft5x06_ts_set_regs(tsdata);
edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
edt_ft5x06_ts_get_parameters(tsdata);
@@ -1285,9 +1302,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (tsdata->version == EDT_M06)
tsdata->report_rate /= 10;
- edt_ft5x06_register_write(tsdata,
- tsdata->reg_addr.reg_report_rate,
- tsdata->report_rate);
+ regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate,
+ tsdata->report_rate);
}
dev_dbg(&client->dev,
@@ -1306,36 +1322,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
touchscreen_parse_properties(input, true, &tsdata->prop);
error = input_mt_init_slots(input, tsdata->max_support_points,
- INPUT_MT_DIRECT);
+ INPUT_MT_DIRECT);
if (error) {
dev_err(&client->dev, "Unable to init MT slots.\n");
return error;
}
- i2c_set_clientdata(client, tsdata);
-
irq_flags = irq_get_trigger_type(client->irq);
if (irq_flags == IRQF_TRIGGER_NONE)
irq_flags = IRQF_TRIGGER_FALLING;
irq_flags |= IRQF_ONESHOT;
error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, edt_ft5x06_ts_isr, irq_flags,
- client->name, tsdata);
+ NULL, edt_ft5x06_ts_isr, irq_flags,
+ client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
}
- error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
- if (error)
- return error;
-
error = input_register_device(input);
if (error)
return error;
- edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
+ edt_ft5x06_ts_prepare_debugfs(tsdata);
dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
@@ -1353,7 +1363,7 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client)
edt_ft5x06_ts_teardown_debugfs(tsdata);
}
-static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
+static int edt_ft5x06_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
@@ -1367,8 +1377,8 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
return 0;
/* Enter hibernate mode. */
- ret = edt_ft5x06_register_write(tsdata, PMOD_REGISTER_OPMODE,
- PMOD_REGISTER_HIBERNATE);
+ ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE,
+ PMOD_REGISTER_HIBERNATE);
if (ret)
dev_warn(dev, "Failed to set hibernate mode\n");
@@ -1396,7 +1406,7 @@ static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
+static int edt_ft5x06_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
@@ -1455,17 +1465,20 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
gpiod_set_value_cansleep(wake_gpio, 1);
}
-
return ret;
}
-static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
- edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
+ edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
static const struct edt_i2c_chip_data edt_ft5x06_data = {
.max_support_points = 5,
};
+static const struct edt_i2c_chip_data edt_ft5452_data = {
+ .max_support_points = 5,
+};
+
static const struct edt_i2c_chip_data edt_ft5506_data = {
.max_support_points = 10,
};
@@ -1474,12 +1487,28 @@ static const struct edt_i2c_chip_data edt_ft6236_data = {
.max_support_points = 2,
};
+static const struct edt_i2c_chip_data edt_ft8201_data = {
+ .max_support_points = 10,
+};
+
+static const struct edt_i2c_chip_data edt_ft8716_data = {
+ .max_support_points = 10,
+};
+
+static const struct edt_i2c_chip_data edt_ft8719_data = {
+ .max_support_points = 10,
+};
+
static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
{ .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
{ .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data },
+ { .name = "ft5452", .driver_data = (long)&edt_ft5452_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
+ { .name = "ft8201", .driver_data = (long)&edt_ft8201_data },
+ { .name = "ft8716", .driver_data = (long)&edt_ft8716_data },
+ { .name = "ft8719", .driver_data = (long)&edt_ft8719_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
@@ -1490,8 +1519,13 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
{ .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data },
+ { .compatible = "focaltech,ft5426", .data = &edt_ft5506_data },
+ { .compatible = "focaltech,ft5452", .data = &edt_ft5452_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
+ { .compatible = "focaltech,ft8201", .data = &edt_ft8201_data },
+ { .compatible = "focaltech,ft8716", .data = &edt_ft8716_data },
+ { .compatible = "focaltech,ft8719", .data = &edt_ft8719_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
@@ -1499,12 +1533,13 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);
static struct i2c_driver edt_ft5x06_ts_driver = {
.driver = {
.name = "edt_ft5x06",
+ .dev_groups = edt_ft5x06_groups,
.of_match_table = edt_ft5x06_of_match,
- .pm = &edt_ft5x06_ts_pm_ops,
+ .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = edt_ft5x06_ts_id,
- .probe_new = edt_ft5x06_ts_probe,
+ .probe = edt_ft5x06_ts_probe,
.remove = edt_ft5x06_ts_remove,
};
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index c8ab03f49227..87eb18977b71 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -21,7 +21,7 @@
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
struct eeti_ts {
struct i2c_client *client;
@@ -232,7 +232,7 @@ static int eeti_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused eeti_ts_suspend(struct device *dev)
+static int eeti_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts *eeti = i2c_get_clientdata(client);
@@ -251,7 +251,7 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused eeti_ts_resume(struct device *dev)
+static int eeti_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct eeti_ts *eeti = i2c_get_clientdata(client);
@@ -270,10 +270,10 @@ static int __maybe_unused eeti_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
static const struct i2c_device_id eeti_ts_id[] = {
- { "eeti_ts", 0 },
+ { "eeti_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
@@ -288,10 +288,10 @@ static const struct of_device_id of_eeti_ts_match[] = {
static struct i2c_driver eeti_ts_driver = {
.driver = {
.name = "eeti_ts",
- .pm = &eeti_ts_pm,
+ .pm = pm_sleep_ptr(&eeti_ts_pm),
.of_match_table = of_match_ptr(of_eeti_ts_match),
},
- .probe_new = eeti_ts_probe,
+ .probe = eeti_ts_probe,
.id_table = eeti_ts_id,
};
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 742d47a75ac1..eb3cc2befcdf 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -23,6 +23,7 @@
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/bitops.h>
#include <linux/input/mt.h>
@@ -102,7 +103,7 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
- down ? "down" : "up", id, x, y, z);
+ str_down_up(down), id, x, y, z);
if (down) {
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
@@ -218,12 +219,12 @@ static int egalax_ts_probe(struct i2c_client *client)
}
static const struct i2c_device_id egalax_ts_id[] = {
- { "egalax_ts", 0 },
+ { "egalax_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
-static int __maybe_unused egalax_ts_suspend(struct device *dev)
+static int egalax_ts_suspend(struct device *dev)
{
static const u8 suspend_cmd[MAX_I2C_DATA_LEN] = {
0x3, 0x6, 0xa, 0x3, 0x36, 0x3f, 0x2, 0, 0, 0
@@ -238,7 +239,7 @@ static int __maybe_unused egalax_ts_suspend(struct device *dev)
return ret > 0 ? 0 : ret;
}
-static int __maybe_unused egalax_ts_resume(struct device *dev)
+static int egalax_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -248,7 +249,8 @@ static int __maybe_unused egalax_ts_resume(struct device *dev)
return egalax_wake_up_device(client);
}
-static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops,
+ egalax_ts_suspend, egalax_ts_resume);
static const struct of_device_id egalax_ts_dt_ids[] = {
{ .compatible = "eeti,egalax_ts" },
@@ -259,11 +261,11 @@ MODULE_DEVICE_TABLE(of, egalax_ts_dt_ids);
static struct i2c_driver egalax_ts_driver = {
.driver = {
.name = "egalax_ts",
- .pm = &egalax_ts_pm_ops,
+ .pm = pm_sleep_ptr(&egalax_ts_pm_ops),
.of_match_table = egalax_ts_dt_ids,
},
.id_table = egalax_ts_id,
- .probe_new = egalax_ts_probe,
+ .probe = egalax_ts_probe,
};
module_i2c_driver(egalax_ts_driver);
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
index 375922d3a6d1..07a4aa1c19bb 100644
--- a/drivers/input/touchscreen/egalax_ts_serial.c
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -99,7 +99,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
+ egalax = kzalloc(sizeof(*egalax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!egalax || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
index 328841eaa1b7..46a0611fac82 100644
--- a/drivers/input/touchscreen/ektf2127.c
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -13,6 +13,7 @@
* Hans de Goede <hdegoede@redhat.com>
*/
+#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -46,6 +47,11 @@ struct ektf2127_ts {
struct input_dev *input;
struct gpio_desc *power_gpios;
struct touchscreen_properties prop;
+ int status_shift;
+};
+
+struct ektf2127_i2c_chip_data {
+ int status_shift;
};
static void ektf2127_parse_coordinates(const u8 *buf, unsigned int touch_count,
@@ -112,8 +118,8 @@ static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot,
static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf)
{
- ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2));
- ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4));
+ ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & BIT(ts->status_shift)));
+ ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & BIT(ts->status_shift + 1)));
input_mt_sync_frame(ts->input);
input_sync(ts->input);
@@ -177,7 +183,7 @@ static void ektf2127_stop(struct input_dev *dev)
gpiod_set_value_cansleep(ts->power_gpios, 0);
}
-static int __maybe_unused ektf2127_suspend(struct device *dev)
+static int ektf2127_suspend(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
@@ -189,7 +195,7 @@ static int __maybe_unused ektf2127_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ektf2127_resume(struct device *dev)
+static int ektf2127_resume(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
@@ -201,8 +207,8 @@ static int __maybe_unused ektf2127_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend,
- ektf2127_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ektf2127_pm_ops, ektf2127_suspend,
+ ektf2127_resume);
static int ektf2127_query_dimension(struct i2c_client *client, bool width)
{
@@ -247,6 +253,7 @@ static int ektf2127_query_dimension(struct i2c_client *client, bool width)
static int ektf2127_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ const struct ektf2127_i2c_chip_data *chip_data;
struct ektf2127_ts *ts;
struct input_dev *input;
u8 buf[4];
@@ -264,12 +271,8 @@ static int ektf2127_probe(struct i2c_client *client)
/* This requests the gpio *and* turns on the touchscreen controller */
ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH);
- if (IS_ERR(ts->power_gpios)) {
- error = PTR_ERR(ts->power_gpios);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Error getting power gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->power_gpios))
+ return dev_err_probe(dev, PTR_ERR(ts->power_gpios), "Error getting power gpio\n");
input = devm_input_allocate_device(dev);
if (!input)
@@ -307,6 +310,13 @@ static int ektf2127_probe(struct i2c_client *client)
return error;
ts->input = input;
+
+ chip_data = i2c_get_match_data(client);
+ if (!chip_data)
+ return dev_err_probe(&client->dev, -EINVAL, "missing chip data\n");
+
+ ts->status_shift = chip_data->status_shift;
+
input_set_drvdata(input, ts);
error = devm_request_threaded_irq(dev, client->irq,
@@ -329,18 +339,28 @@ static int ektf2127_probe(struct i2c_client *client)
return 0;
}
+static const struct ektf2127_i2c_chip_data ektf2127_data = {
+ .status_shift = 1,
+};
+
+static const struct ektf2127_i2c_chip_data ektf2232_data = {
+ .status_shift = 0,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id ektf2127_of_match[] = {
- { .compatible = "elan,ektf2127" },
- { .compatible = "elan,ektf2132" },
+ { .compatible = "elan,ektf2127", .data = &ektf2127_data},
+ { .compatible = "elan,ektf2132", .data = &ektf2127_data},
+ { .compatible = "elan,ektf2232", .data = &ektf2232_data},
{}
};
MODULE_DEVICE_TABLE(of, ektf2127_of_match);
#endif
static const struct i2c_device_id ektf2127_i2c_id[] = {
- { "ektf2127", 0 },
- { "ektf2132", 0 },
+ { .name = "ektf2127", .driver_data = (long)&ektf2127_data },
+ { .name = "ektf2132", .driver_data = (long)&ektf2127_data },
+ { .name = "ektf2232", .driver_data = (long)&ektf2232_data },
{}
};
MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
@@ -348,10 +368,10 @@ MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
static struct i2c_driver ektf2127_driver = {
.driver = {
.name = "elan_ektf2127",
- .pm = &ektf2127_pm_ops,
+ .pm = pm_sleep_ptr(&ektf2127_pm_ops),
.of_match_table = of_match_ptr(ektf2127_of_match),
},
- .probe_new = ektf2127_probe,
+ .probe = ektf2127_probe,
.id_table = ektf2127_i2c_id,
};
module_i2c_driver(ektf2127_driver);
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 5452b50f8a77..3fd170f75b4a 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -40,7 +40,7 @@
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/uuid.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Device, Driver information */
#define DEVICE_NAME "elants_i2c"
@@ -1299,7 +1299,7 @@ static ELANTS_VERSION_ATTR(solution_version);
static ELANTS_VERSION_ATTR(bc_version);
static ELANTS_VERSION_ATTR(iap_version);
-static struct attribute *elants_attributes[] = {
+static struct attribute *elants_i2c_attrs[] = {
&dev_attr_calibrate.attr,
&dev_attr_update_fw.attr,
&dev_attr_iap_mode.attr,
@@ -1313,10 +1313,7 @@ static struct attribute *elants_attributes[] = {
&elants_ver_attr_iap_version.dattr.attr,
NULL
};
-
-static const struct attribute_group elants_attribute_group = {
- .attrs = elants_attributes,
-};
+ATTRIBUTE_GROUPS(elants_i2c);
static int elants_i2c_power_on(struct elants_data *ts)
{
@@ -1438,24 +1435,14 @@ static int elants_i2c_probe(struct i2c_client *client)
i2c_set_clientdata(client, ts);
ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
- if (IS_ERR(ts->vcc33)) {
- error = PTR_ERR(ts->vcc33);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get 'vcc33' regulator: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(ts->vcc33))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->vcc33),
+ "Failed to get 'vcc33' regulator\n");
ts->vccio = devm_regulator_get(&client->dev, "vccio");
- if (IS_ERR(ts->vccio)) {
- error = PTR_ERR(ts->vccio);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get 'vccio' regulator: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(ts->vccio))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->vccio),
+ "Failed to get 'vccio' regulator\n");
ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ts->reset_gpio)) {
@@ -1562,17 +1549,10 @@ static int elants_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &elants_attribute_group);
- if (error) {
- dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
- error);
- return error;
- }
-
return 0;
}
-static int __maybe_unused elants_i2c_suspend(struct device *dev)
+static int elants_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
@@ -1611,7 +1591,7 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused elants_i2c_resume(struct device *dev)
+static int elants_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elants_data *ts = i2c_get_clientdata(client);
@@ -1644,8 +1624,8 @@ static int __maybe_unused elants_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
- elants_i2c_suspend, elants_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
+ elants_i2c_suspend, elants_i2c_resume);
static const struct i2c_device_id elants_i2c_id[] = {
{ DEVICE_NAME, EKTH3500 },
@@ -1673,11 +1653,12 @@ MODULE_DEVICE_TABLE(of, elants_of_match);
#endif
static struct i2c_driver elants_i2c_driver = {
- .probe_new = elants_i2c_probe,
+ .probe = elants_i2c_probe,
.id_table = elants_i2c_id,
.driver = {
.name = DEVICE_NAME,
- .pm = &elants_i2c_pm_ops,
+ .dev_groups = elants_i2c_groups,
+ .pm = pm_sleep_ptr(&elants_i2c_pm_ops),
.acpi_match_table = ACPI_PTR(elants_acpi_id),
.of_match_table = of_match_ptr(elants_of_match),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 96173232e53f..ad209e6e82a6 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -225,10 +225,10 @@ static int elo_command_10(struct elo *elo, unsigned char *packet)
mutex_lock(&elo->cmd_mutex);
- serio_pause_rx(elo->serio);
- elo->expected_packet = toupper(packet[0]);
- init_completion(&elo->cmd_done);
- serio_continue_rx(elo->serio);
+ scoped_guard(serio_pause_rx, elo->serio) {
+ elo->expected_packet = toupper(packet[0]);
+ init_completion(&elo->cmd_done);
+ }
if (serio_write(elo->serio, ELO10_LEAD_BYTE))
goto out;
@@ -307,7 +307,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- elo = kzalloc(sizeof(struct elo), GFP_KERNEL);
+ elo = kzalloc(sizeof(*elo), GFP_KERNEL);
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index 4b7eee01c6aa..28da7ba55a4b 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -7,6 +7,7 @@
* minimal implementation based on egalax_ts.c and egalax_i2c.c
*/
+#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -18,9 +19,10 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/timer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define EXC3000_NUM_SLOTS 10
#define EXC3000_SLOTS_PER_FRAME 5
@@ -51,6 +53,7 @@ enum eeti_dev_id {
EETI_EXC3000,
EETI_EXC80H60,
EETI_EXC80H84,
+ EETI_EXC81W32,
};
static struct eeti_dev_info exc3000_info[] = {
@@ -66,6 +69,10 @@ static struct eeti_dev_info exc3000_info[] = {
.name = "EETI EXC80H84 Touch Screen",
.max_xy = SZ_16K - 1,
},
+ [EETI_EXC81W32] = {
+ .name = "EETI EXC81W32 Touch Screen",
+ .max_xy = SZ_16K - 1,
+ },
};
struct exc3000_data {
@@ -98,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input,
static void exc3000_timer(struct timer_list *t)
{
- struct exc3000_data *data = from_timer(data, t, timer);
+ struct exc3000_data *data = timer_container_of(data, t, timer);
input_mt_sync_frame(data->input);
input_sync(data->input);
@@ -109,6 +116,11 @@ static inline void exc3000_schedule_timer(struct exc3000_data *data)
mod_timer(&data->timer, jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
}
+static void exc3000_shutdown_timer(void *timer)
+{
+ timer_shutdown_sync(timer);
+}
+
static int exc3000_read_frame(struct exc3000_data *data, u8 *buf)
{
struct i2c_client *client = data->client;
@@ -162,7 +174,7 @@ static int exc3000_handle_mt_event(struct exc3000_data *data)
/*
* We read full state successfully, no contacts will be "stuck".
*/
- del_timer_sync(&data->timer);
+ timer_delete_sync(&data->timer);
while (total_slots > 0) {
int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
@@ -318,16 +330,13 @@ static ssize_t type_show(struct device *dev,
}
static DEVICE_ATTR_RO(type);
-static struct attribute *sysfs_attrs[] = {
+static struct attribute *exc3000_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_model.attr,
&dev_attr_type.attr,
NULL
};
-
-static struct attribute_group exc3000_attribute_group = {
- .attrs = sysfs_attrs
-};
+ATTRIBUTE_GROUPS(exc3000);
static int exc3000_probe(struct i2c_client *client)
{
@@ -355,6 +364,12 @@ static int exc3000_probe(struct i2c_client *client)
if (IS_ERR(data->reset))
return PTR_ERR(data->reset);
+ /* For proper reset sequence, enable power while reset asserted */
+ error = devm_regulator_get_enable(&client->dev, "vdd");
+ if (error && error != -ENODEV)
+ return dev_err_probe(&client->dev, error,
+ "failed to request vdd regulator\n");
+
if (data->reset) {
msleep(EXC3000_RESET_MS);
gpiod_set_value_cansleep(data->reset, 0);
@@ -386,6 +401,11 @@ static int exc3000_probe(struct i2c_client *client)
if (error)
return error;
+ error = devm_add_action_or_reset(&client->dev, exc3000_shutdown_timer,
+ &data->timer);
+ if (error)
+ return error;
+
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, exc3000_interrupt, IRQF_ONESHOT,
client->name, data);
@@ -419,10 +439,6 @@ static int exc3000_probe(struct i2c_client *client)
i2c_set_clientdata(client, data);
- error = devm_device_add_group(&client->dev, &exc3000_attribute_group);
- if (error)
- return error;
-
return 0;
}
@@ -430,6 +446,7 @@ static const struct i2c_device_id exc3000_id[] = {
{ "exc3000", EETI_EXC3000 },
{ "exc80h60", EETI_EXC80H60 },
{ "exc80h84", EETI_EXC80H84 },
+ { "exc81w32", EETI_EXC81W32 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
@@ -439,18 +456,29 @@ static const struct of_device_id exc3000_of_match[] = {
{ .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] },
{ .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] },
{ .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] },
+ { .compatible = "eeti,exc81w32", .data = &exc3000_info[EETI_EXC81W32] },
{ }
};
MODULE_DEVICE_TABLE(of, exc3000_of_match);
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id exc3000_acpi_match[] = {
+ { "EGA00001", .driver_data = (kernel_ulong_t)&exc3000_info[EETI_EXC80H60] },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, exc3000_acpi_match);
+#endif
+
static struct i2c_driver exc3000_driver = {
.driver = {
.name = "exc3000",
+ .dev_groups = exc3000_groups,
.of_match_table = of_match_ptr(exc3000_of_match),
+ .acpi_match_table = ACPI_PTR(exc3000_acpi_match),
},
.id_table = exc3000_id,
- .probe_new = exc3000_probe,
+ .probe = exc3000_probe,
};
module_i2c_driver(exc3000_driver);
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index 60a7246c5157..ff270b3b8572 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -38,8 +38,7 @@ struct mx25_tcq_priv {
struct device *dev;
};
-static struct regmap_config mx25_tcq_regconfig = {
- .fast_io = true,
+static const struct regmap_config mx25_tcq_regconfig = {
.max_register = 0x5c,
.reg_bits = 32,
.val_bits = 32,
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index 3b0b8fccc3f0..1a3e14ea2e08 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -99,7 +99,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+ fujitsu = kzalloc(sizeof(*fujitsu), GFP_KERNEL);
input_dev = input_allocate_device();
if (!fujitsu || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 8a0a8078de8f..f8798d11ec03 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "goodix.h"
#define GOODIX_GPIO_INT_NAME "irq"
@@ -44,9 +44,11 @@
#define GOODIX_HAVE_KEY BIT(4)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
-#define RESOLUTION_LOC 1
-#define MAX_CONTACTS_LOC 5
-#define TRIGGER_LOC 6
+#define RESOLUTION_LOC 1
+#define MAX_CONTACTS_LOC 5
+#define TRIGGER_LOC 6
+
+#define GOODIX_POLL_INTERVAL_MS 17 /* 17ms = 60fps */
/* Our special handling for GPIO accesses through ACPI is x86 specific */
#if defined CONFIG_X86 && defined CONFIG_ACPI
@@ -124,10 +126,18 @@ static const unsigned long goodix_irq_flags[] = {
static const struct dmi_system_id nine_bytes_report[] = {
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
{
- .ident = "Lenovo YogaBook",
- /* YB1-X91L/F and YB1-X90L/F */
+ /* Lenovo Yoga Book X90F / X90L */
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
+ }
+ },
+ {
+ /* Lenovo Yoga Book X91F / X91L */
+ .matches = {
+ /* Non exact match to match F + L versions */
+ DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
}
},
#endif
@@ -489,6 +499,14 @@ sync:
input_sync(ts->input_dev);
}
+static void goodix_ts_work_i2c_poll(struct input_dev *input)
+{
+ struct goodix_ts_data *ts = input_get_drvdata(input);
+
+ goodix_process_events(ts);
+ goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
+}
+
/**
* goodix_ts_irq_handler - The IRQ handler
*
@@ -505,13 +523,29 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void goodix_enable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ enable_irq(ts->client->irq);
+}
+
+static void goodix_disable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ disable_irq(ts->client->irq);
+}
+
static void goodix_free_irq(struct goodix_ts_data *ts)
{
- devm_free_irq(&ts->client->dev, ts->client->irq, ts);
+ if (ts->client->irq)
+ devm_free_irq(&ts->client->dev, ts->client->irq, ts);
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
+ if (!ts->client->irq)
+ return 0;
+
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
@@ -762,17 +796,6 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
usleep_range(6000, 10000); /* T4: > 5ms */
- /*
- * Put the reset pin back in to input / high-impedance mode to save
- * power. Only do this in the non ACPI case since some ACPI boards
- * don't have a pull-up, so there the reset pin must stay active-high.
- */
- if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
- error = gpiod_direction_input(ts->gpiod_rst);
- if (error)
- goto error;
- }
-
return 0;
error:
@@ -876,7 +899,8 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
}
}
- if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
+ /* Some devices with gpio_int_idx 0 list a third unused GPIO */
+ if ((ts->gpio_count == 2 || ts->gpio_count == 3) && ts->gpio_int_idx == 0) {
ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
gpio_mapping = acpi_goodix_int_first_gpios;
} else if (ts->gpio_count == 2 && ts->gpio_int_idx == 1) {
@@ -892,6 +916,25 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
gpio_mapping = acpi_goodix_int_last_gpios;
+ } else if (ts->gpio_count == 1 && ts->gpio_int_idx == 0) {
+ /*
+ * On newer devices there is only 1 GpioInt resource and _PS0
+ * does the whole reset sequence for us.
+ */
+ acpi_device_fix_up_power(ACPI_COMPANION(dev));
+
+ /*
+ * Before the _PS0 call the int GPIO may have been in output
+ * mode and the call should have put the int GPIO in input mode,
+ * but the GPIO subsys cached state may still think it is
+ * in output mode, causing gpiochip_lock_as_irq() failure.
+ *
+ * Add a mapping for the int GPIO to make the
+ * gpiod_int = gpiod_get(..., GPIOD_IN) call succeed,
+ * which will explicitly set the direction to input.
+ */
+ ts->irq_pin_access_method = IRQ_PIN_ACCESS_NONE;
+ gpio_mapping = acpi_goodix_int_first_gpios;
} else {
dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
ts->gpio_count, ts->gpio_int_idx);
@@ -903,14 +946,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
return -EINVAL;
}
- /*
- * Normally we put the reset pin in input / high-impedance mode to save
- * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
- * case, leave the pin as is. This results in the pin not being touched
- * at all on x86/ACPI boards, except when needed for error-recover.
- */
- ts->gpiod_rst_flags = GPIOD_ASIS;
-
return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
}
#else
@@ -927,7 +962,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
*/
static int goodix_get_gpio_config(struct goodix_ts_data *ts)
{
- int error;
struct device *dev;
struct gpio_desc *gpiod;
bool added_acpi_mappings = false;
@@ -936,40 +970,21 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
return -EINVAL;
dev = &ts->client->dev;
- /*
- * By default we request the reset pin as input, leaving it in
- * high-impedance when not resetting the controller to save power.
- */
- ts->gpiod_rst_flags = GPIOD_IN;
-
ts->avdd28 = devm_regulator_get(dev, "AVDD28");
- if (IS_ERR(ts->avdd28)) {
- error = PTR_ERR(ts->avdd28);
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get AVDD28 regulator: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->avdd28))
+ return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n");
ts->vddio = devm_regulator_get(dev, "VDDIO");
- if (IS_ERR(ts->vddio)) {
- error = PTR_ERR(ts->vddio);
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get VDDIO regulator: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->vddio))
+ return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n");
retry_get_irq_gpio:
/* Get the interrupt GPIO pin number */
gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN);
- if (IS_ERR(gpiod)) {
- error = PTR_ERR(gpiod);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get %s GPIO: %d\n",
- GOODIX_GPIO_INT_NAME, error);
- return error;
- }
+ if (IS_ERR(gpiod))
+ return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
+ GOODIX_GPIO_INT_NAME);
+
if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) {
added_acpi_mappings = true;
if (goodix_add_acpi_gpio_mappings(ts) == 0)
@@ -979,14 +994,10 @@ retry_get_irq_gpio:
ts->gpiod_int = gpiod;
/* Get the reset line GPIO pin number */
- gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
- if (IS_ERR(gpiod)) {
- error = PTR_ERR(gpiod);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get %s GPIO: %d\n",
- GOODIX_GPIO_RST_NAME, error);
- return error;
- }
+ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_ASIS);
+ if (IS_ERR(gpiod))
+ return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
+ GOODIX_GPIO_RST_NAME);
ts->gpiod_rst = gpiod;
@@ -1209,6 +1220,18 @@ retry_read_config:
return error;
}
+ input_set_drvdata(ts->input_dev, ts);
+
+ if (!ts->client->irq) {
+ error = input_setup_polling(ts->input_dev, goodix_ts_work_i2c_poll);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "could not set up polling mode, %d\n", error);
+ return error;
+ }
+ input_set_poll_interval(ts->input_dev, GOODIX_POLL_INTERVAL_MS);
+ }
+
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,
@@ -1401,7 +1424,7 @@ static void goodix_ts_remove(struct i2c_client *client)
wait_for_completion(&ts->firmware_loading_complete);
}
-static int __maybe_unused goodix_suspend(struct device *dev)
+static int goodix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
@@ -1412,7 +1435,7 @@ static int __maybe_unused goodix_suspend(struct device *dev)
/* We need gpio pins to suspend/resume */
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- disable_irq(client->irq);
+ goodix_disable_irq(ts);
return 0;
}
@@ -1448,7 +1471,7 @@ static int __maybe_unused goodix_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused goodix_resume(struct device *dev)
+static int goodix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct goodix_ts_data *ts = i2c_get_clientdata(client);
@@ -1456,7 +1479,7 @@ static int __maybe_unused goodix_resume(struct device *dev)
int error;
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- enable_irq(client->irq);
+ goodix_enable_irq(ts);
return 0;
}
@@ -1497,10 +1520,10 @@ static int __maybe_unused goodix_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
static const struct i2c_device_id goodix_ts_id[] = {
- { "GDIX1001:00", 0 },
+ { "GDIX1001:00" },
{ }
};
MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
@@ -1509,6 +1532,8 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
static const struct acpi_device_id goodix_acpi_match[] = {
{ "GDIX1001", 0 },
{ "GDIX1002", 0 },
+ { "GDIX1003", 0 },
+ { "GDX9110", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
@@ -1536,14 +1561,14 @@ MODULE_DEVICE_TABLE(of, goodix_of_match);
#endif
static struct i2c_driver goodix_ts_driver = {
- .probe_new = goodix_ts_probe,
+ .probe = goodix_ts_probe,
.remove = goodix_ts_remove,
.id_table = goodix_ts_id,
.driver = {
.name = "Goodix-TS",
.acpi_match_table = ACPI_PTR(goodix_acpi_match),
.of_match_table = of_match_ptr(goodix_of_match),
- .pm = &goodix_pm_ops,
+ .pm = pm_sleep_ptr(&goodix_pm_ops),
},
};
module_i2c_driver(goodix_ts_driver);
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 87797cc88b32..0d1e8a8d2cba 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -88,7 +88,6 @@ struct goodix_ts_data {
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
- enum gpiod_flags gpiod_rst_flags;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
u16 version;
diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h
new file mode 100644
index 000000000000..d8bbd4853206
--- /dev/null
+++ b/drivers/input/touchscreen/goodix_berlin.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Goodix Touchscreen Driver
+ * Copyright (C) 2020 - 2021 Goodix, Inc.
+ * Copyright (C) 2023 Linaro Ltd.
+ *
+ * Based on goodix_berlin_berlin driver.
+ */
+
+#ifndef __GOODIX_BERLIN_H_
+#define __GOODIX_BERLIN_H_
+
+#include <linux/pm.h>
+
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A 0x1000C
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D 0x10014
+
+#define GOODIX_BERLIN_IC_INFO_ADDR_A 0x10068
+#define GOODIX_BERLIN_IC_INFO_ADDR_D 0x10070
+
+struct goodix_berlin_ic_data {
+ int fw_version_info_addr;
+ int ic_info_addr;
+ ssize_t read_dummy_len;
+ ssize_t read_prefix_len;
+};
+
+struct device;
+struct input_id;
+struct regmap;
+
+int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data);
+
+extern const struct dev_pm_ops goodix_berlin_pm_ops;
+extern const struct attribute_group *goodix_berlin_groups[];
+
+#endif
diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c
new file mode 100644
index 000000000000..83f28b870531
--- /dev/null
+++ b/drivers/input/touchscreen/goodix_berlin_core.c
@@ -0,0 +1,802 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Goodix "Berlin" Touchscreen IC driver
+ * Copyright (C) 2020 - 2021 Goodix, Inc.
+ * Copyright (C) 2023 Linaro Ltd.
+ *
+ * Based on goodix_ts_berlin driver.
+ *
+ * This driver is distinct from goodix.c since hardware interface
+ * is different enough to require a new driver.
+ * None of the register address or data structure are close enough
+ * to the previous generations.
+ *
+ * Currently the driver only handles Multitouch events with already
+ * programmed firmware and "config" for "Revision A/D" Berlin IC.
+ *
+ * Support is missing for:
+ * - ESD Management
+ * - Firmware update/flashing
+ * - "Config" update/flashing
+ * - Stylus Events
+ * - Gesture Events
+ * - Support for revision B
+ */
+
+#include <linux/bitfield.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sizes.h>
+#include <linux/unaligned.h>
+
+#include "goodix_berlin.h"
+
+#define GOODIX_BERLIN_MAX_TOUCH 10
+
+#define GOODIX_BERLIN_NORMAL_RESET_DELAY_MS 100
+
+#define GOODIX_BERLIN_TOUCH_EVENT BIT(7)
+#define GOODIX_BERLIN_REQUEST_EVENT BIT(6)
+#define GOODIX_BERLIN_TOUCH_COUNT_MASK GENMASK(3, 0)
+
+#define GOODIX_BERLIN_REQUEST_CODE_RESET 3
+
+#define GOODIX_BERLIN_POINT_TYPE_MASK GENMASK(3, 0)
+#define GOODIX_BERLIN_POINT_TYPE_STYLUS_HOVER 1
+#define GOODIX_BERLIN_POINT_TYPE_STYLUS 3
+
+#define GOODIX_BERLIN_TOUCH_ID_MASK GENMASK(7, 4)
+
+#define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA
+#define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000
+
+#define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K
+
+#define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16)
+
+struct goodix_berlin_fw_version {
+ u8 rom_pid[6];
+ u8 rom_vid[3];
+ u8 rom_vid_reserved;
+ u8 patch_pid[8];
+ u8 patch_vid[4];
+ u8 patch_vid_reserved;
+ u8 sensor_id;
+ u8 reserved[2];
+ __le16 checksum;
+};
+
+struct goodix_berlin_ic_info_version {
+ u8 info_customer_id;
+ u8 info_version_id;
+ u8 ic_die_id;
+ u8 ic_version_id;
+ __le32 config_id;
+ u8 config_version;
+ u8 frame_data_customer_id;
+ u8 frame_data_version_id;
+ u8 touch_data_customer_id;
+ u8 touch_data_version_id;
+ u8 reserved[3];
+} __packed;
+
+struct goodix_berlin_ic_info_feature {
+ __le16 freqhop_feature;
+ __le16 calibration_feature;
+ __le16 gesture_feature;
+ __le16 side_touch_feature;
+ __le16 stylus_feature;
+} __packed;
+
+struct goodix_berlin_ic_info_misc {
+ __le32 cmd_addr;
+ __le16 cmd_max_len;
+ __le32 cmd_reply_addr;
+ __le16 cmd_reply_len;
+ __le32 fw_state_addr;
+ __le16 fw_state_len;
+ __le32 fw_buffer_addr;
+ __le16 fw_buffer_max_len;
+ __le32 frame_data_addr;
+ __le16 frame_data_head_len;
+ __le16 fw_attr_len;
+ __le16 fw_log_len;
+ u8 pack_max_num;
+ u8 pack_compress_version;
+ __le16 stylus_struct_len;
+ __le16 mutual_struct_len;
+ __le16 self_struct_len;
+ __le16 noise_struct_len;
+ __le32 touch_data_addr;
+ __le16 touch_data_head_len;
+ __le16 point_struct_len;
+ __le16 reserved1;
+ __le16 reserved2;
+ __le32 mutual_rawdata_addr;
+ __le32 mutual_diffdata_addr;
+ __le32 mutual_refdata_addr;
+ __le32 self_rawdata_addr;
+ __le32 self_diffdata_addr;
+ __le32 self_refdata_addr;
+ __le32 iq_rawdata_addr;
+ __le32 iq_refdata_addr;
+ __le32 im_rawdata_addr;
+ __le16 im_readata_len;
+ __le32 noise_rawdata_addr;
+ __le16 noise_rawdata_len;
+ __le32 stylus_rawdata_addr;
+ __le16 stylus_rawdata_len;
+ __le32 noise_data_addr;
+ __le32 esd_addr;
+} __packed;
+
+struct goodix_berlin_touch {
+ u8 status;
+ u8 reserved;
+ __le16 x;
+ __le16 y;
+ __le16 w;
+};
+#define GOODIX_BERLIN_TOUCH_SIZE sizeof(struct goodix_berlin_touch)
+
+struct goodix_berlin_header {
+ u8 status;
+ u8 reserved1;
+ u8 request_type;
+ u8 reserved2[3];
+ __le16 checksum;
+};
+#define GOODIX_BERLIN_HEADER_SIZE sizeof(struct goodix_berlin_header)
+
+struct goodix_berlin_event {
+ struct goodix_berlin_header hdr;
+ /* The data below is u16/__le16 aligned */
+ u8 data[GOODIX_BERLIN_TOUCH_SIZE * GOODIX_BERLIN_MAX_TOUCH +
+ GOODIX_BERLIN_CHECKSUM_SIZE];
+};
+
+struct goodix_berlin_core {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator *avdd;
+ struct regulator *vddio;
+ struct gpio_desc *reset_gpio;
+ struct touchscreen_properties props;
+ struct goodix_berlin_fw_version fw_version;
+ struct input_dev *input_dev;
+ int irq;
+
+ /* Runtime parameters extracted from IC_INFO buffer */
+ u32 touch_data_addr;
+
+ const struct goodix_berlin_ic_data *ic_data;
+
+ struct goodix_berlin_event event;
+};
+
+static bool goodix_berlin_checksum_valid(const u8 *data, int size)
+{
+ u32 cal_checksum = 0;
+ u16 r_checksum;
+ int i;
+
+ if (size < GOODIX_BERLIN_CHECKSUM_SIZE)
+ return false;
+
+ for (i = 0; i < size - GOODIX_BERLIN_CHECKSUM_SIZE; i++)
+ cal_checksum += data[i];
+
+ r_checksum = get_unaligned_le16(&data[i]);
+
+ return (u16)cal_checksum == r_checksum;
+}
+
+static bool goodix_berlin_is_dummy_data(struct goodix_berlin_core *cd,
+ const u8 *data, int size)
+{
+ int i;
+
+ /*
+ * If the device is missing or doesn't respond the buffer
+ * could be filled with bus default line state, 0x00 or 0xff,
+ * so declare success the first time we encounter neither.
+ */
+ for (i = 0; i < size; i++)
+ if (data[i] > 0 && data[i] < 0xff)
+ return false;
+
+ return true;
+}
+
+static int goodix_berlin_dev_confirm(struct goodix_berlin_core *cd)
+{
+ u8 tx_buf[8], rx_buf[8];
+ int retry = 3;
+ int error;
+
+ memset(tx_buf, GOODIX_BERLIN_DEV_CONFIRM_VAL, sizeof(tx_buf));
+ while (retry--) {
+ error = regmap_raw_write(cd->regmap,
+ GOODIX_BERLIN_BOOTOPTION_ADDR,
+ tx_buf, sizeof(tx_buf));
+ if (error)
+ return error;
+
+ error = regmap_raw_read(cd->regmap,
+ GOODIX_BERLIN_BOOTOPTION_ADDR,
+ rx_buf, sizeof(rx_buf));
+ if (error)
+ return error;
+
+ if (!memcmp(tx_buf, rx_buf, sizeof(tx_buf)))
+ return 0;
+
+ usleep_range(5000, 5100);
+ }
+
+ dev_err(cd->dev, "device confirm failed, rx_buf: %*ph\n",
+ (int)sizeof(rx_buf), rx_buf);
+
+ return -EINVAL;
+}
+
+static int goodix_berlin_power_on(struct goodix_berlin_core *cd)
+{
+ int error;
+
+ error = regulator_enable(cd->vddio);
+ if (error) {
+ dev_err(cd->dev, "Failed to enable vddio: %d\n", error);
+ return error;
+ }
+
+ /* Vendor waits 3ms for VDDIO to settle */
+ usleep_range(3000, 3100);
+
+ error = regulator_enable(cd->avdd);
+ if (error) {
+ dev_err(cd->dev, "Failed to enable avdd: %d\n", error);
+ goto err_vddio_disable;
+ }
+
+ /* Vendor waits 15ms for AVDD to settle */
+ usleep_range(15000, 15100);
+
+ gpiod_set_value_cansleep(cd->reset_gpio, 0);
+
+ /* Vendor waits 4ms for Firmware to initialize */
+ usleep_range(4000, 4100);
+
+ error = goodix_berlin_dev_confirm(cd);
+ if (error)
+ goto err_dev_reset;
+
+ /* Vendor waits 100ms for Firmware to fully boot */
+ msleep(GOODIX_BERLIN_NORMAL_RESET_DELAY_MS);
+
+ return 0;
+
+err_dev_reset:
+ gpiod_set_value_cansleep(cd->reset_gpio, 1);
+ regulator_disable(cd->avdd);
+err_vddio_disable:
+ regulator_disable(cd->vddio);
+ return error;
+}
+
+static void goodix_berlin_power_off(struct goodix_berlin_core *cd)
+{
+ gpiod_set_value_cansleep(cd->reset_gpio, 1);
+ regulator_disable(cd->avdd);
+ regulator_disable(cd->vddio);
+}
+
+static int goodix_berlin_read_version(struct goodix_berlin_core *cd)
+{
+ int error;
+
+ error = regmap_raw_read(cd->regmap, cd->ic_data->fw_version_info_addr,
+ &cd->fw_version, sizeof(cd->fw_version));
+ if (error) {
+ dev_err(cd->dev, "error reading fw version, %d\n", error);
+ return error;
+ }
+
+ if (!goodix_berlin_checksum_valid((u8 *)&cd->fw_version,
+ sizeof(cd->fw_version))) {
+ dev_err(cd->dev, "invalid fw version: checksum error\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Only extract necessary data for runtime */
+static int goodix_berlin_parse_ic_info(struct goodix_berlin_core *cd,
+ const u8 *data, u16 length)
+{
+ struct goodix_berlin_ic_info_misc *misc;
+ unsigned int offset = 0;
+
+ offset += sizeof(__le16); /* length */
+ offset += sizeof(struct goodix_berlin_ic_info_version);
+ offset += sizeof(struct goodix_berlin_ic_info_feature);
+
+ /* IC_INFO Parameters, variable width structure */
+ offset += 4 * sizeof(u8); /* drv_num, sen_num, button_num, force_num */
+ if (offset >= length)
+ goto invalid_offset;
+
+#define ADVANCE_LE16_PARAMS() \
+ do { \
+ u8 param_num = data[offset++]; \
+ offset += param_num * sizeof(__le16); \
+ if (offset >= length) \
+ goto invalid_offset; \
+ } while (0)
+ ADVANCE_LE16_PARAMS(); /* active_scan_rate_num */
+ ADVANCE_LE16_PARAMS(); /* mutual_freq_num*/
+ ADVANCE_LE16_PARAMS(); /* self_tx_freq_num */
+ ADVANCE_LE16_PARAMS(); /* self_rx_freq_num */
+ ADVANCE_LE16_PARAMS(); /* stylus_freq_num */
+#undef ADVANCE_LE16_PARAMS
+
+ misc = (struct goodix_berlin_ic_info_misc *)&data[offset];
+ cd->touch_data_addr = le32_to_cpu(misc->touch_data_addr);
+
+ return 0;
+
+invalid_offset:
+ dev_err(cd->dev, "ic_info length is invalid (offset %d length %d)\n",
+ offset, length);
+ return -EINVAL;
+}
+
+static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
+{
+ u8 *afe_data __free(kfree) = NULL;
+ __le16 length_raw;
+ u16 length;
+ int error;
+
+ afe_data = kzalloc(GOODIX_BERLIN_IC_INFO_MAX_LEN, GFP_KERNEL);
+ if (!afe_data)
+ return -ENOMEM;
+
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr,
+ &length_raw, sizeof(length_raw));
+ if (error) {
+ dev_err(cd->dev, "failed get ic info length, %d\n", error);
+ return error;
+ }
+
+ length = le16_to_cpu(length_raw);
+ if (length >= GOODIX_BERLIN_IC_INFO_MAX_LEN) {
+ dev_err(cd->dev, "invalid ic info length %d\n", length);
+ return -EINVAL;
+ }
+
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, afe_data,
+ length);
+ if (error) {
+ dev_err(cd->dev, "failed get ic info data, %d\n", error);
+ return error;
+ }
+
+ /* check whether the data is valid (ex. bus default values) */
+ if (goodix_berlin_is_dummy_data(cd, afe_data, length)) {
+ dev_err(cd->dev, "fw info data invalid\n");
+ return -EINVAL;
+ }
+
+ if (!goodix_berlin_checksum_valid(afe_data, length)) {
+ dev_err(cd->dev, "fw info checksum error\n");
+ return -EINVAL;
+ }
+
+ error = goodix_berlin_parse_ic_info(cd, afe_data, length);
+ if (error)
+ return error;
+
+ /* check some key info */
+ if (!cd->touch_data_addr) {
+ dev_err(cd->dev, "touch_data_addr is null\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int goodix_berlin_get_remaining_contacts(struct goodix_berlin_core *cd,
+ int n)
+{
+ size_t offset = 2 * GOODIX_BERLIN_TOUCH_SIZE +
+ GOODIX_BERLIN_CHECKSUM_SIZE;
+ u32 addr = cd->touch_data_addr + GOODIX_BERLIN_HEADER_SIZE + offset;
+ int error;
+
+ error = regmap_raw_read(cd->regmap, addr,
+ &cd->event.data[offset],
+ (n - 2) * GOODIX_BERLIN_TOUCH_SIZE);
+ if (error) {
+ dev_err_ratelimited(cd->dev, "failed to get touch data, %d\n",
+ error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void goodix_berlin_report_state(struct goodix_berlin_core *cd, int n)
+{
+ struct goodix_berlin_touch *touch_data =
+ (struct goodix_berlin_touch *)cd->event.data;
+ struct goodix_berlin_touch *t;
+ int i;
+ u8 type, id;
+
+ for (i = 0; i < n; i++) {
+ t = &touch_data[i];
+
+ type = FIELD_GET(GOODIX_BERLIN_POINT_TYPE_MASK, t->status);
+ if (type == GOODIX_BERLIN_POINT_TYPE_STYLUS ||
+ type == GOODIX_BERLIN_POINT_TYPE_STYLUS_HOVER) {
+ dev_warn_once(cd->dev, "Stylus event type not handled\n");
+ continue;
+ }
+
+ id = FIELD_GET(GOODIX_BERLIN_TOUCH_ID_MASK, t->status);
+ if (id >= GOODIX_BERLIN_MAX_TOUCH) {
+ dev_warn_ratelimited(cd->dev, "invalid finger id %d\n", id);
+ continue;
+ }
+
+ input_mt_slot(cd->input_dev, id);
+ input_mt_report_slot_state(cd->input_dev, MT_TOOL_FINGER, true);
+
+ touchscreen_report_pos(cd->input_dev, &cd->props,
+ __le16_to_cpu(t->x), __le16_to_cpu(t->y),
+ true);
+ input_report_abs(cd->input_dev, ABS_MT_TOUCH_MAJOR,
+ __le16_to_cpu(t->w));
+ }
+
+ input_mt_sync_frame(cd->input_dev);
+ input_sync(cd->input_dev);
+}
+
+static void goodix_berlin_touch_handler(struct goodix_berlin_core *cd)
+{
+ u8 touch_num;
+ int error;
+
+ touch_num = FIELD_GET(GOODIX_BERLIN_TOUCH_COUNT_MASK,
+ cd->event.hdr.request_type);
+ if (touch_num > GOODIX_BERLIN_MAX_TOUCH) {
+ dev_warn(cd->dev, "invalid touch num %d\n", touch_num);
+ return;
+ }
+
+ if (touch_num > 2) {
+ /* read additional contact data if more than 2 touch events */
+ error = goodix_berlin_get_remaining_contacts(cd, touch_num);
+ if (error)
+ return;
+ }
+
+ if (touch_num) {
+ int len = touch_num * GOODIX_BERLIN_TOUCH_SIZE +
+ GOODIX_BERLIN_CHECKSUM_SIZE;
+ if (!goodix_berlin_checksum_valid(cd->event.data, len)) {
+ dev_err(cd->dev, "touch data checksum error: %*ph\n",
+ len, cd->event.data);
+ return;
+ }
+ }
+
+ goodix_berlin_report_state(cd, touch_num);
+}
+
+static int goodix_berlin_request_handle_reset(struct goodix_berlin_core *cd)
+{
+ gpiod_set_value_cansleep(cd->reset_gpio, 1);
+ usleep_range(2000, 2100);
+ gpiod_set_value_cansleep(cd->reset_gpio, 0);
+
+ msleep(GOODIX_BERLIN_NORMAL_RESET_DELAY_MS);
+
+ return 0;
+}
+
+static irqreturn_t goodix_berlin_irq(int irq, void *data)
+{
+ struct goodix_berlin_core *cd = data;
+ int error;
+
+ /*
+ * First, read buffer with space for 2 touch events:
+ * - GOODIX_BERLIN_HEADER_SIZE = 8 bytes
+ * - GOODIX_BERLIN_TOUCH_SIZE * 2 = 16 bytes
+ * - GOODIX_BERLIN_CHECKLSUM_SIZE = 2 bytes
+ * For a total of 26 bytes.
+ *
+ * If only a single finger is reported, we will read 8 bytes more than
+ * needed:
+ * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE)
+ * - bytes 8-15: Finger 0 Data
+ * - bytes 24-25: Checksum
+ * - bytes 18-25: Unused 8 bytes
+ *
+ * If 2 fingers are reported, we would have read the exact needed
+ * amount of data and checksum would be at the end of the buffer:
+ * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE)
+ * - bytes 8-15: Finger 0 Bytes 0-7
+ * - bytes 16-23: Finger 1 Bytes 0-7
+ * - bytes 24-25: Checksum
+ *
+ * If more than 2 fingers were reported, the "Checksum" bytes would
+ * in fact contain part of the next finger data, and then
+ * goodix_berlin_get_remaining_contacts() would complete the buffer
+ * with the missing bytes, including the trailing checksum.
+ * For example, if 3 fingers are reported, then we would do:
+ * Read 1:
+ * - bytes 0-7: Header (GOODIX_BERLIN_HEADER_SIZE)
+ * - bytes 8-15: Finger 0 Bytes 0-7
+ * - bytes 16-23: Finger 1 Bytes 0-7
+ * - bytes 24-25: Finger 2 Bytes 0-1
+ * Read 2 (with length of (3 - 2) * 8 = 8 bytes):
+ * - bytes 26-31: Finger 2 Bytes 2-7
+ * - bytes 32-33: Checksum
+ */
+ error = regmap_raw_read(cd->regmap, cd->touch_data_addr,
+ &cd->event,
+ GOODIX_BERLIN_HEADER_SIZE +
+ 2 * GOODIX_BERLIN_TOUCH_SIZE +
+ GOODIX_BERLIN_CHECKSUM_SIZE);
+ if (error) {
+ dev_warn_ratelimited(cd->dev,
+ "failed get event head data: %d\n", error);
+ goto out;
+ }
+
+ if (cd->event.hdr.status == 0)
+ goto out;
+
+ if (!goodix_berlin_checksum_valid((u8 *)&cd->event.hdr,
+ GOODIX_BERLIN_HEADER_SIZE)) {
+ dev_warn_ratelimited(cd->dev,
+ "touch head checksum error: %*ph\n",
+ (int)GOODIX_BERLIN_HEADER_SIZE,
+ &cd->event.hdr);
+ goto out_clear;
+ }
+
+ if (cd->event.hdr.status & GOODIX_BERLIN_TOUCH_EVENT)
+ goodix_berlin_touch_handler(cd);
+
+ if (cd->event.hdr.status & GOODIX_BERLIN_REQUEST_EVENT) {
+ switch (cd->event.hdr.request_type) {
+ case GOODIX_BERLIN_REQUEST_CODE_RESET:
+ if (cd->reset_gpio)
+ goodix_berlin_request_handle_reset(cd);
+ break;
+
+ default:
+ dev_warn(cd->dev, "unsupported request code 0x%x\n",
+ cd->event.hdr.request_type);
+ }
+ }
+
+
+out_clear:
+ /* Clear up status field */
+ regmap_write(cd->regmap, cd->touch_data_addr, 0);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd,
+ const struct input_id *id)
+{
+ struct input_dev *input_dev;
+ int error;
+
+ input_dev = devm_input_allocate_device(cd->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ cd->input_dev = input_dev;
+ input_set_drvdata(input_dev, cd);
+
+ input_dev->name = "Goodix Berlin Capacitive TouchScreen";
+ input_dev->phys = "input/ts";
+
+ input_dev->id = *id;
+
+ input_set_abs_params(cd->input_dev, ABS_MT_POSITION_X,
+ 0, SZ_64K - 1, 0, 0);
+ input_set_abs_params(cd->input_dev, ABS_MT_POSITION_Y,
+ 0, SZ_64K - 1, 0, 0);
+ input_set_abs_params(cd->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+ touchscreen_parse_properties(cd->input_dev, true, &cd->props);
+
+ error = input_mt_init_slots(cd->input_dev, GOODIX_BERLIN_MAX_TOUCH,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (error)
+ return error;
+
+ error = input_register_device(cd->input_dev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int goodix_berlin_suspend(struct device *dev)
+{
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+
+ disable_irq(cd->irq);
+ goodix_berlin_power_off(cd);
+
+ return 0;
+}
+
+static int goodix_berlin_resume(struct device *dev)
+{
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+ int error;
+
+ error = goodix_berlin_power_on(cd);
+ if (error)
+ return error;
+
+ enable_irq(cd->irq);
+
+ return 0;
+}
+
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(goodix_berlin_pm_ops,
+ goodix_berlin_suspend, goodix_berlin_resume);
+
+static void goodix_berlin_power_off_act(void *data)
+{
+ struct goodix_berlin_core *cd = data;
+
+ goodix_berlin_power_off(cd);
+}
+
+static ssize_t registers_read(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+ int error;
+
+ error = regmap_raw_read(cd->regmap, off, buf, count);
+
+ return error ? error : count;
+}
+
+static ssize_t registers_write(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+ int error;
+
+ error = regmap_raw_write(cd->regmap, off, buf, count);
+
+ return error ? error : count;
+}
+
+static const BIN_ATTR_ADMIN_RW(registers, 0);
+
+static const struct bin_attribute *const goodix_berlin_bin_attrs[] = {
+ &bin_attr_registers,
+ NULL,
+};
+
+static const struct attribute_group goodix_berlin_attr_group = {
+ .bin_attrs = goodix_berlin_bin_attrs,
+};
+
+const struct attribute_group *goodix_berlin_groups[] = {
+ &goodix_berlin_attr_group,
+ NULL,
+};
+EXPORT_SYMBOL_GPL(goodix_berlin_groups);
+
+int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data)
+{
+ struct goodix_berlin_core *cd;
+ int error;
+
+ if (irq <= 0) {
+ dev_err(dev, "Missing interrupt number\n");
+ return -EINVAL;
+ }
+
+ cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL);
+ if (!cd)
+ return -ENOMEM;
+
+ cd->dev = dev;
+ cd->regmap = regmap;
+ cd->irq = irq;
+ cd->ic_data = ic_data;
+
+ cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(cd->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(cd->reset_gpio),
+ "Failed to request reset gpio\n");
+
+ cd->avdd = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(cd->avdd))
+ return dev_err_probe(dev, PTR_ERR(cd->avdd),
+ "Failed to request avdd regulator\n");
+
+ cd->vddio = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(cd->vddio))
+ return dev_err_probe(dev, PTR_ERR(cd->vddio),
+ "Failed to request vddio regulator\n");
+
+ error = goodix_berlin_power_on(cd);
+ if (error) {
+ dev_err(dev, "failed power on");
+ return error;
+ }
+
+ error = devm_add_action_or_reset(dev, goodix_berlin_power_off_act, cd);
+ if (error)
+ return error;
+
+ error = goodix_berlin_read_version(cd);
+ if (error) {
+ dev_err(dev, "failed to get version info");
+ return error;
+ }
+
+ error = goodix_berlin_get_ic_info(cd);
+ if (error) {
+ dev_err(dev, "invalid ic info, abort");
+ return error;
+ }
+
+ error = goodix_berlin_input_dev_config(cd, id);
+ if (error) {
+ dev_err(dev, "failed set input device");
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, cd->irq, NULL, goodix_berlin_irq,
+ IRQF_ONESHOT, "goodix-berlin", cd);
+ if (error) {
+ dev_err(dev, "request threaded irq failed: %d\n", error);
+ return error;
+ }
+
+ dev_set_drvdata(dev, cd);
+
+ dev_dbg(dev, "Goodix Berlin %s Touchscreen Controller",
+ cd->fw_version.patch_pid);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(goodix_berlin_probe);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Goodix Berlin Core Touchscreen driver");
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c
new file mode 100644
index 000000000000..929090a094bf
--- /dev/null
+++ b/drivers/input/touchscreen/goodix_berlin_i2c.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Goodix Berlin Touchscreen Driver
+ *
+ * Copyright (C) 2020 - 2021 Goodix, Inc.
+ * Copyright (C) 2023 Linaro Ltd.
+ *
+ * Based on goodix_ts_berlin driver.
+ */
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/input.h>
+
+#include "goodix_berlin.h"
+
+#define I2C_MAX_TRANSFER_SIZE 256
+
+static const struct regmap_config goodix_berlin_i2c_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .max_raw_read = I2C_MAX_TRANSFER_SIZE,
+ .max_raw_write = I2C_MAX_TRANSFER_SIZE,
+};
+
+/* vendor & product left unassigned here, should probably be updated from fw info */
+static const struct input_id goodix_berlin_i2c_input_id = {
+ .bustype = BUS_I2C,
+};
+
+static int goodix_berlin_i2c_probe(struct i2c_client *client)
+{
+ const struct goodix_berlin_ic_data *ic_data =
+ i2c_get_match_data(client);
+ struct regmap *regmap;
+ int error;
+
+ regmap = devm_regmap_init_i2c(client, &goodix_berlin_i2c_regmap_conf);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ error = goodix_berlin_probe(&client->dev, client->irq,
+ &goodix_berlin_i2c_input_id, regmap,
+ ic_data);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+};
+
+static const struct i2c_device_id goodix_berlin_i2c_id[] = {
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id);
+
+static const struct of_device_id goodix_berlin_i2c_of_match[] = {
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);
+
+static struct i2c_driver goodix_berlin_i2c_driver = {
+ .driver = {
+ .name = "goodix-berlin-i2c",
+ .of_match_table = goodix_berlin_i2c_of_match,
+ .pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
+ .dev_groups = goodix_berlin_groups,
+ },
+ .probe = goodix_berlin_i2c_probe,
+ .id_table = goodix_berlin_i2c_id,
+};
+module_i2c_driver(goodix_berlin_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Goodix Berlin I2C Touchscreen driver");
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c
new file mode 100644
index 000000000000..01f850f484c2
--- /dev/null
+++ b/drivers/input/touchscreen/goodix_berlin_spi.c
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Goodix Berlin Touchscreen Driver
+ *
+ * Copyright (C) 2020 - 2021 Goodix, Inc.
+ * Copyright (C) 2023 Linaro Ltd.
+ *
+ * Based on goodix_ts_berlin driver.
+ */
+#include <linux/unaligned.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+
+#include "goodix_berlin.h"
+
+#define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1
+#define GOODIX_BERLIN_REGISTER_WIDTH 4
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A 4
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D 3
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+ GOODIX_BERLIN_REGISTER_WIDTH + \
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A)
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+ GOODIX_BERLIN_REGISTER_WIDTH + \
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D)
+#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+ GOODIX_BERLIN_REGISTER_WIDTH)
+
+#define GOODIX_BERLIN_SPI_WRITE_FLAG 0xF0
+#define GOODIX_BERLIN_SPI_READ_FLAG 0xF1
+
+static int goodix_berlin_spi_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf,
+ size_t val_size)
+{
+ struct spi_device *spi = context;
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
+ struct spi_transfer xfers;
+ struct spi_message spi_msg;
+ const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */
+ int error;
+
+ if (reg_size != GOODIX_BERLIN_REGISTER_WIDTH)
+ return -EINVAL;
+
+ u8 *buf __free(kfree) =
+ kzalloc(ic_data->read_prefix_len + val_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ spi_message_init(&spi_msg);
+ memset(&xfers, 0, sizeof(xfers));
+
+ /* buffer format: 0xF1 + addr(4bytes) + dummy(3/4bytes) + data */
+ buf[0] = GOODIX_BERLIN_SPI_READ_FLAG;
+ put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
+ memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH,
+ 0xff, ic_data->read_dummy_len);
+
+ xfers.tx_buf = buf;
+ xfers.rx_buf = buf;
+ xfers.len = ic_data->read_prefix_len + val_size;
+ xfers.cs_change = 0;
+ spi_message_add_tail(&xfers, &spi_msg);
+
+ error = spi_sync(spi, &spi_msg);
+ if (error < 0) {
+ dev_err(&spi->dev, "spi transfer error, %d", error);
+ return error;
+ }
+
+ memcpy(val_buf, buf + ic_data->read_prefix_len, val_size);
+ return error;
+}
+
+static int goodix_berlin_spi_write(void *context, const void *data,
+ size_t count)
+{
+ unsigned int len = count - GOODIX_BERLIN_REGISTER_WIDTH;
+ struct spi_device *spi = context;
+ struct spi_transfer xfers;
+ struct spi_message spi_msg;
+ const u32 *reg = data; /* reg is stored as native u32 at start of buffer */
+ int error;
+
+ u8 *buf __free(kfree) =
+ kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ spi_message_init(&spi_msg);
+ memset(&xfers, 0, sizeof(xfers));
+
+ buf[0] = GOODIX_BERLIN_SPI_WRITE_FLAG;
+ put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
+ memcpy(buf + GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN,
+ data + GOODIX_BERLIN_REGISTER_WIDTH, len);
+
+ xfers.tx_buf = buf;
+ xfers.len = GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len;
+ xfers.cs_change = 0;
+ spi_message_add_tail(&xfers, &spi_msg);
+
+ error = spi_sync(spi, &spi_msg);
+ if (error < 0) {
+ dev_err(&spi->dev, "spi transfer error, %d", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct regmap_config goodix_berlin_spi_regmap_conf = {
+ .reg_bits = 32,
+ .val_bits = 8,
+ .read = goodix_berlin_spi_read,
+ .write = goodix_berlin_spi_write,
+};
+
+/* vendor & product left unassigned here, should probably be updated from fw info */
+static const struct input_id goodix_berlin_spi_input_id = {
+ .bustype = BUS_SPI,
+};
+
+static int goodix_berlin_spi_probe(struct spi_device *spi)
+{
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
+ struct regmap_config regmap_config;
+ struct regmap *regmap;
+ size_t max_size;
+ int error = 0;
+
+ spi->mode = SPI_MODE_0;
+ spi->bits_per_word = 8;
+ error = spi_setup(spi);
+ if (error)
+ return error;
+
+ max_size = spi_max_transfer_size(spi);
+
+ regmap_config = goodix_berlin_spi_regmap_conf;
+ regmap_config.max_raw_read = max_size - ic_data->read_prefix_len;
+ regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN;
+
+ regmap = devm_regmap_init(&spi->dev, NULL, spi, &regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ error = goodix_berlin_probe(&spi->dev, spi->irq,
+ &goodix_berlin_spi_input_id, regmap,
+ ic_data);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static const struct goodix_berlin_ic_data gt9897_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_A,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A,
+};
+
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D,
+};
+
+static const struct spi_device_id goodix_berlin_spi_ids[] = {
+ { .name = "gt9897", .driver_data = (long)&gt9897_data },
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
+ { },
+};
+MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids);
+
+static const struct of_device_id goodix_berlin_spi_of_match[] = {
+ { .compatible = "goodix,gt9897", .data = &gt9897_data },
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);
+
+static struct spi_driver goodix_berlin_spi_driver = {
+ .driver = {
+ .name = "goodix-berlin-spi",
+ .of_match_table = goodix_berlin_spi_of_match,
+ .pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
+ .dev_groups = goodix_berlin_groups,
+ },
+ .probe = goodix_berlin_spi_probe,
+ .id_table = goodix_berlin_spi_ids,
+};
+module_spi_driver(goodix_berlin_spi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Goodix Berlin SPI Touchscreen driver");
+MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 5a5f9da73fa1..dbf92fb02f80 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -97,7 +97,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL);
+ gunze = kzalloc(sizeof(*gunze), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gunze || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index 5c4d877564ee..dc0a2482ddd6 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -109,7 +109,7 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
+ phampshire = kzalloc(sizeof(*phampshire), GFP_KERNEL);
input_dev = input_allocate_device();
if (!phampshire || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index ff4bb4c14898..a73369e15dda 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -17,7 +17,7 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HIDEEP_TS_NAME "HiDeep Touchscreen"
#define HIDEEP_I2C_NAME "hideep_ts"
@@ -35,6 +35,7 @@
#define HIDEEP_EVENT_ADDR 0x240
/* command list */
+#define HIDEEP_WORK_MODE 0x081e
#define HIDEEP_RESET_CMD 0x9800
/* event bit */
@@ -271,9 +272,14 @@ static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val)
#define SW_RESET_IN_PGM(clk) \
{ \
+ __be32 data = cpu_to_be32(0x01); \
hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \
hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \
- hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x01); \
+ /* \
+ * The first write may already cause a reset, use a raw \
+ * write for the second write to avoid error logging. \
+ */ \
+ hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \
}
#define SET_FLASH_PIO(ce) \
@@ -467,9 +473,9 @@ static int hideep_program_nvm(struct hideep_ts *ts,
u32 addr = 0;
int error;
- error = hideep_nvm_unlock(ts);
- if (error)
- return error;
+ error = hideep_nvm_unlock(ts);
+ if (error)
+ return error;
while (ucode_len > 0) {
xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
@@ -922,8 +928,7 @@ static ssize_t hideep_fw_version_show(struct device *dev,
ssize_t len;
mutex_lock(&ts->dev_mutex);
- len = scnprintf(buf, PAGE_SIZE, "%04x\n",
- be16_to_cpu(ts->dwz_info.release_ver));
+ len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver));
mutex_unlock(&ts->dev_mutex);
return len;
@@ -937,8 +942,7 @@ static ssize_t hideep_product_id_show(struct device *dev,
ssize_t len;
mutex_lock(&ts->dev_mutex);
- len = scnprintf(buf, PAGE_SIZE, "%04x\n",
- be16_to_cpu(ts->dwz_info.product_id));
+ len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id));
mutex_unlock(&ts->dev_mutex);
return len;
@@ -948,18 +952,30 @@ static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL);
static DEVICE_ATTR(product_id, 0664, hideep_product_id_show, NULL);
static DEVICE_ATTR(update_fw, 0664, NULL, hideep_update_fw);
-static struct attribute *hideep_ts_sysfs_entries[] = {
+static struct attribute *hideep_ts_attrs[] = {
&dev_attr_version.attr,
&dev_attr_product_id.attr,
&dev_attr_update_fw.attr,
NULL,
};
+ATTRIBUTE_GROUPS(hideep_ts);
-static const struct attribute_group hideep_ts_attr_group = {
- .attrs = hideep_ts_sysfs_entries,
-};
+static void hideep_set_work_mode(struct hideep_ts *ts)
+{
+ /*
+ * Reset touch report format to the native HiDeep 20 protocol if requested.
+ * This is necessary to make touchscreens which come up in I2C-HID mode
+ * work with this driver.
+ *
+ * Note this is a kernel internal device-property set by x86 platform code,
+ * this MUST not be used in devicetree files without first adding it to
+ * the DT bindings.
+ */
+ if (device_property_read_bool(&ts->client->dev, "hideep,force-native-protocol"))
+ regmap_write(ts->reg, HIDEEP_WORK_MODE, 0x00);
+}
-static int __maybe_unused hideep_suspend(struct device *dev)
+static int hideep_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -970,7 +986,7 @@ static int __maybe_unused hideep_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused hideep_resume(struct device *dev)
+static int hideep_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
@@ -982,12 +998,14 @@ static int __maybe_unused hideep_resume(struct device *dev)
return error;
}
+ hideep_set_work_mode(ts);
+
enable_irq(client->irq);
return 0;
}
-static SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
static const struct regmap_config hideep_regmap_config = {
.reg_bits = 16,
@@ -1058,6 +1076,8 @@ static int hideep_probe(struct i2c_client *client)
return error;
}
+ hideep_set_work_mode(ts);
+
error = hideep_init_input(ts);
if (error)
return error;
@@ -1071,18 +1091,11 @@ static int hideep_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &hideep_ts_attr_group);
- if (error) {
- dev_err(&client->dev,
- "failed to add sysfs attributes: %d\n", error);
- return error;
- }
-
return 0;
}
static const struct i2c_device_id hideep_i2c_id[] = {
- { HIDEEP_I2C_NAME, 0 },
+ { HIDEEP_I2C_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, hideep_i2c_id);
@@ -1106,12 +1119,13 @@ MODULE_DEVICE_TABLE(of, hideep_match_table);
static struct i2c_driver hideep_driver = {
.driver = {
.name = HIDEEP_I2C_NAME,
+ .dev_groups = hideep_ts_groups,
.of_match_table = of_match_ptr(hideep_match_table),
.acpi_match_table = ACPI_PTR(hideep_acpi_id),
- .pm = &hideep_pm_ops,
+ .pm = pm_sleep_ptr(&hideep_pm_ops),
},
.id_table = hideep_i2c_id,
- .probe_new = hideep_probe,
+ .probe = hideep_probe,
};
module_i2c_driver(hideep_driver);
diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c
index e96150d80a48..896a145ddb2b 100644
--- a/drivers/input/touchscreen/himax_hx83112b.c
+++ b/drivers/input/touchscreen/himax_hx83112b.c
@@ -4,6 +4,9 @@
*
* Copyright (C) 2022 Job Noorman <job@noorman.info>
*
+ * HX83100A support
+ * Copyright (C) 2024 Felix Kaechele <felix@kaechele.ca>
+ *
* This code is based on "Himax Android Driver Sample Code for QCT platform":
*
* Copyright (C) 2017 Himax Corporation.
@@ -20,16 +23,22 @@
#include <linux/kernel.h>
#include <linux/regmap.h>
-#define HIMAX_ID_83112B 0x83112b
-
#define HIMAX_MAX_POINTS 10
-#define HIMAX_REG_CFG_SET_ADDR 0x00
-#define HIMAX_REG_CFG_INIT_READ 0x0c
-#define HIMAX_REG_CFG_READ_VALUE 0x08
-#define HIMAX_REG_READ_EVENT 0x30
+#define HIMAX_AHB_ADDR_BYTE_0 0x00
+#define HIMAX_AHB_ADDR_RDATA_BYTE_0 0x08
+#define HIMAX_AHB_ADDR_ACCESS_DIRECTION 0x0c
+#define HIMAX_AHB_ADDR_INCR4 0x0d
+#define HIMAX_AHB_ADDR_CONTI 0x13
+#define HIMAX_AHB_ADDR_EVENT_STACK 0x30
+
+#define HIMAX_AHB_CMD_ACCESS_DIRECTION_READ 0x00
+#define HIMAX_AHB_CMD_INCR4 0x10
+#define HIMAX_AHB_CMD_CONTI 0x31
-#define HIMAX_CFG_PRODUCT_ID 0x900000d0
+#define HIMAX_REG_ADDR_ICID 0x900000d0
+
+#define HX83100A_REG_FW_EVENT_STACK 0x90060000
#define HIMAX_INVALID_COORD 0xffff
@@ -49,7 +58,16 @@ struct himax_event {
static_assert(sizeof(struct himax_event) == 56);
+struct himax_ts_data;
+struct himax_chip {
+ u32 id;
+ int (*check_id)(struct himax_ts_data *ts);
+ int (*read_events)(struct himax_ts_data *ts, struct himax_event *event,
+ size_t length);
+};
+
struct himax_ts_data {
+ const struct himax_chip *chip;
struct gpio_desc *gpiod_rst;
struct input_dev *input_dev;
struct i2c_client *client;
@@ -63,19 +81,49 @@ static const struct regmap_config himax_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
-static int himax_read_config(struct himax_ts_data *ts, u32 address, u32 *dst)
+static int himax_bus_enable_burst(struct himax_ts_data *ts)
+{
+ int error;
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_CONTI,
+ HIMAX_AHB_CMD_CONTI);
+ if (error)
+ return error;
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_INCR4,
+ HIMAX_AHB_CMD_INCR4);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int himax_bus_read(struct himax_ts_data *ts, u32 address, void *dst,
+ size_t length)
{
int error;
- error = regmap_write(ts->regmap, HIMAX_REG_CFG_SET_ADDR, address);
+ if (length > 4) {
+ error = himax_bus_enable_burst(ts);
+ if (error)
+ return error;
+ }
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_BYTE_0, address);
if (error)
return error;
- error = regmap_write(ts->regmap, HIMAX_REG_CFG_INIT_READ, 0x0);
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_ACCESS_DIRECTION,
+ HIMAX_AHB_CMD_ACCESS_DIRECTION_READ);
if (error)
return error;
- error = regmap_read(ts->regmap, HIMAX_REG_CFG_READ_VALUE, dst);
+ if (length > 4)
+ error = regmap_noinc_read(ts->regmap, HIMAX_AHB_ADDR_RDATA_BYTE_0,
+ dst, length);
+ else
+ error = regmap_read(ts->regmap, HIMAX_AHB_ADDR_RDATA_BYTE_0,
+ dst);
if (error)
return error;
@@ -101,7 +149,8 @@ static int himax_read_product_id(struct himax_ts_data *ts, u32 *product_id)
{
int error;
- error = himax_read_config(ts, HIMAX_CFG_PRODUCT_ID, product_id);
+ error = himax_bus_read(ts, HIMAX_REG_ADDR_ICID, product_id,
+ sizeof(*product_id));
if (error)
return error;
@@ -120,15 +169,12 @@ static int himax_check_product_id(struct himax_ts_data *ts)
dev_dbg(&ts->client->dev, "Product id: %x\n", product_id);
- switch (product_id) {
- case HIMAX_ID_83112B:
+ if (product_id == ts->chip->id)
return 0;
- default:
- dev_err(&ts->client->dev,
- "Unknown product id: %x\n", product_id);
- return -EINVAL;
- }
+ dev_err(&ts->client->dev, "Unknown product id: %x\n",
+ product_id);
+ return -EINVAL;
}
static int himax_input_register(struct himax_ts_data *ts)
@@ -230,13 +276,25 @@ static bool himax_verify_checksum(struct himax_ts_data *ts,
return true;
}
+static int himax_read_events(struct himax_ts_data *ts,
+ struct himax_event *event, size_t length)
+{
+ return regmap_raw_read(ts->regmap, HIMAX_AHB_ADDR_EVENT_STACK, event,
+ length);
+}
+
+static int hx83100a_read_events(struct himax_ts_data *ts,
+ struct himax_event *event, size_t length)
+{
+ return himax_bus_read(ts, HX83100A_REG_FW_EVENT_STACK, event, length);
+};
+
static int himax_handle_input(struct himax_ts_data *ts)
{
int error;
struct himax_event event;
- error = regmap_raw_read(ts->regmap, HIMAX_REG_READ_EVENT, &event,
- sizeof(event));
+ error = ts->chip->read_events(ts, &event, sizeof(event));
if (error) {
dev_err(&ts->client->dev, "Failed to read input event: %d\n",
error);
@@ -282,6 +340,7 @@ static int himax_probe(struct i2c_client *client)
i2c_set_clientdata(client, ts);
ts->client = client;
+ ts->chip = i2c_get_match_data(client);
ts->regmap = devm_regmap_init_i2c(client, &himax_regmap_config);
error = PTR_ERR_OR_ZERO(ts->regmap);
@@ -299,9 +358,11 @@ static int himax_probe(struct i2c_client *client)
himax_reset(ts);
- error = himax_check_product_id(ts);
- if (error)
- return error;
+ if (ts->chip->check_id) {
+ error = himax_check_product_id(ts);
+ if (error)
+ return error;
+ }
error = himax_input_register(ts);
if (error)
@@ -334,22 +395,34 @@ static int himax_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(himax_pm_ops, himax_suspend, himax_resume);
+static const struct himax_chip hx83100a_chip = {
+ .read_events = hx83100a_read_events,
+};
+
+static const struct himax_chip hx83112b_chip = {
+ .id = 0x83112b,
+ .check_id = himax_check_product_id,
+ .read_events = himax_read_events,
+};
+
static const struct i2c_device_id himax_ts_id[] = {
- { "hx83112b", 0 },
+ { "hx83100a", (kernel_ulong_t)&hx83100a_chip },
+ { "hx83112b", (kernel_ulong_t)&hx83112b_chip },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, himax_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id himax_of_match[] = {
- { .compatible = "himax,hx83112b" },
+ { .compatible = "himax,hx83100a", .data = &hx83100a_chip },
+ { .compatible = "himax,hx83112b", .data = &hx83112b_chip },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, himax_of_match);
#endif
static struct i2c_driver himax_ts_driver = {
- .probe_new = himax_probe,
+ .probe = himax_probe,
.id_table = himax_ts_id,
.driver = {
.name = "Himax-hx83112b-TS",
diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c
new file mode 100644
index 000000000000..83c60e137a55
--- /dev/null
+++ b/drivers/input/touchscreen/himax_hx852x.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Himax HX852x(ES) Touchscreen Driver
+ * Copyright (c) 2020-2024 Stephan Gerhold <stephan@gerhold.net>
+ * Copyright (c) 2020 Jonathan Albrieux <jonathan.albrieux@gmail.com>
+ *
+ * Based on the Himax Android Driver Sample Code Ver 0.3 for HMX852xES chipset:
+ * Copyright (c) 2014 Himax Corporation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/unaligned.h>
+
+#define HX852X_COORD_SIZE(fingers) ((fingers) * sizeof(struct hx852x_coord))
+#define HX852X_WIDTH_SIZE(fingers) ALIGN(fingers, 4)
+#define HX852X_BUF_SIZE(fingers) (HX852X_COORD_SIZE(fingers) + \
+ HX852X_WIDTH_SIZE(fingers) + \
+ sizeof(struct hx852x_touch_info))
+
+#define HX852X_MAX_FINGERS 12
+#define HX852X_MAX_KEY_COUNT 4
+#define HX852X_MAX_BUF_SIZE HX852X_BUF_SIZE(HX852X_MAX_FINGERS)
+
+#define HX852X_TS_SLEEP_IN 0x80
+#define HX852X_TS_SLEEP_OUT 0x81
+#define HX852X_TS_SENSE_OFF 0x82
+#define HX852X_TS_SENSE_ON 0x83
+#define HX852X_READ_ONE_EVENT 0x85
+#define HX852X_READ_ALL_EVENTS 0x86
+#define HX852X_READ_LATEST_EVENT 0x87
+#define HX852X_CLEAR_EVENT_STACK 0x88
+
+#define HX852X_REG_SRAM_SWITCH 0x8c
+#define HX852X_REG_SRAM_ADDR 0x8b
+#define HX852X_REG_FLASH_RPLACE 0x5a
+
+#define HX852X_SRAM_SWITCH_TEST_MODE 0x14
+#define HX852X_SRAM_ADDR_CONFIG 0x7000
+
+struct hx852x {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct touchscreen_properties props;
+ struct gpio_desc *reset_gpiod;
+ struct regulator_bulk_data supplies[2];
+ unsigned int max_fingers;
+ unsigned int keycount;
+ unsigned int keycodes[HX852X_MAX_KEY_COUNT];
+};
+
+struct hx852x_config {
+ u8 rx_num;
+ u8 tx_num;
+ u8 max_pt;
+ u8 padding1[3];
+ __be16 x_res;
+ __be16 y_res;
+ u8 padding2[2];
+} __packed __aligned(4);
+
+struct hx852x_coord {
+ __be16 x;
+ __be16 y;
+} __packed __aligned(4);
+
+struct hx852x_touch_info {
+ u8 finger_num;
+ __le16 finger_pressed;
+ u8 padding;
+} __packed __aligned(4);
+
+static int hx852x_i2c_read(struct hx852x *hx, u8 cmd, void *data, u16 len)
+{
+ struct i2c_client *client = hx->client;
+ int error;
+ int ret;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &cmd,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&client->dev, "failed to read %#x: %d\n", cmd, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_power_on(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_enable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to enable regulators: %d\n", error);
+ return error;
+ }
+
+ gpiod_set_value_cansleep(hx->reset_gpiod, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(hx->reset_gpiod, 0);
+ msleep(50);
+
+ return 0;
+}
+
+static int hx852x_start(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_OUT);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_OUT: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_ON);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_ON: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ return 0;
+}
+
+static int hx852x_stop(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_OFF);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_OFF: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_IN);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_IN: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ return 0;
+}
+
+static int hx852x_power_off(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_disable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to disable regulators: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_read_config(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ struct hx852x_config conf;
+ int x_res, y_res;
+ int error, error2;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ /* Sensing must be turned on briefly to load the config */
+ error = hx852x_start(hx);
+ if (error)
+ goto err_power_off;
+
+ error = hx852x_stop(hx);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH,
+ HX852X_SRAM_SWITCH_TEST_MODE);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_word_data(hx->client, HX852X_REG_SRAM_ADDR,
+ HX852X_SRAM_ADDR_CONFIG);
+ if (error)
+ goto err_test_mode;
+
+ error = hx852x_i2c_read(hx, HX852X_REG_FLASH_RPLACE, &conf, sizeof(conf));
+ if (error)
+ goto err_test_mode;
+
+ x_res = be16_to_cpu(conf.x_res);
+ y_res = be16_to_cpu(conf.y_res);
+ hx->max_fingers = (conf.max_pt & 0xf0) >> 4;
+ dev_dbg(dev, "x res: %u, y res: %u, max fingers: %u\n",
+ x_res, y_res, hx->max_fingers);
+
+ if (hx->max_fingers > HX852X_MAX_FINGERS) {
+ dev_err(dev, "max supported fingers: %u, found: %u\n",
+ HX852X_MAX_FINGERS, hx->max_fingers);
+ error = -EINVAL;
+ goto err_test_mode;
+ }
+
+ if (x_res && y_res) {
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_X, 0, x_res - 1, 0, 0);
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_Y, 0, y_res - 1, 0, 0);
+ }
+
+err_test_mode:
+ error2 = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, 0);
+ error = error ?: error2;
+err_power_off:
+ error2 = hx852x_power_off(hx);
+ return error ?: error2;
+}
+
+static int hx852x_handle_events(struct hx852x *hx)
+{
+ /*
+ * The event packets have variable size, depending on the amount of
+ * supported fingers (hx->max_fingers). They are laid out as follows:
+ * - struct hx852x_coord[hx->max_fingers]: Coordinates for each finger
+ * - u8[ALIGN(hx->max_fingers, 4)]: Touch width for each finger
+ * with padding for 32-bit alignment
+ * - struct hx852x_touch_info
+ *
+ * Load everything into a 32-bit aligned buffer so the coordinates
+ * can be assigned directly, without using get_unaligned_*().
+ */
+ u8 buf[HX852X_MAX_BUF_SIZE] __aligned(4);
+ struct hx852x_coord *coord = (struct hx852x_coord *)buf;
+ u8 *width = &buf[HX852X_COORD_SIZE(hx->max_fingers)];
+ struct hx852x_touch_info *info = (struct hx852x_touch_info *)
+ &width[HX852X_WIDTH_SIZE(hx->max_fingers)];
+ unsigned long finger_pressed, key_pressed;
+ unsigned int i, x, y, w;
+ int error;
+
+ error = hx852x_i2c_read(hx, HX852X_READ_ALL_EVENTS, buf,
+ HX852X_BUF_SIZE(hx->max_fingers));
+ if (error)
+ return error;
+
+ finger_pressed = get_unaligned_le16(&info->finger_pressed);
+ key_pressed = finger_pressed >> HX852X_MAX_FINGERS;
+
+ /* All bits are set when no touch is detected */
+ if (info->finger_num == 0xff || !(info->finger_num & 0x0f))
+ finger_pressed = 0;
+ if (key_pressed == 0xf)
+ key_pressed = 0;
+
+ for_each_set_bit(i, &finger_pressed, hx->max_fingers) {
+ x = be16_to_cpu(coord[i].x);
+ y = be16_to_cpu(coord[i].y);
+ w = width[i];
+
+ input_mt_slot(hx->input_dev, i);
+ input_mt_report_slot_state(hx->input_dev, MT_TOOL_FINGER, 1);
+ touchscreen_report_pos(hx->input_dev, &hx->props, x, y, true);
+ input_report_abs(hx->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ }
+ input_mt_sync_frame(hx->input_dev);
+
+ for (i = 0; i < hx->keycount; i++)
+ input_report_key(hx->input_dev, hx->keycodes[i], key_pressed & BIT(i));
+
+ input_sync(hx->input_dev);
+ return 0;
+}
+
+static irqreturn_t hx852x_interrupt(int irq, void *ptr)
+{
+ struct hx852x *hx = ptr;
+ int error;
+
+ error = hx852x_handle_events(hx);
+ if (error) {
+ dev_err_ratelimited(&hx->client->dev,
+ "failed to handle events: %d\n", error);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hx852x_input_open(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+ int error;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ error = hx852x_start(hx);
+ if (error) {
+ hx852x_power_off(hx);
+ return error;
+ }
+
+ enable_irq(hx->client->irq);
+ return 0;
+}
+
+static void hx852x_input_close(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+
+ hx852x_stop(hx);
+ disable_irq(hx->client->irq);
+ hx852x_power_off(hx);
+}
+
+static int hx852x_parse_properties(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error, count;
+
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count == -EINVAL) {
+ /* Property does not exist, keycodes are optional */
+ return 0;
+ } else if (count < 0) {
+ dev_err(dev, "Failed to read linux,keycodes: %d\n", count);
+ return count;
+ } else if (count > HX852X_MAX_KEY_COUNT) {
+ dev_err(dev, "max supported keys: %u, found: %u\n",
+ HX852X_MAX_KEY_COUNT, hx->keycount);
+ return -EINVAL;
+ }
+ hx->keycount = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ hx->keycodes, hx->keycount);
+ if (error) {
+ dev_err(dev, "failed to read linux,keycodes: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct hx852x *hx;
+ int error, i;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
+ dev_err(dev, "not all required i2c functionality supported\n");
+ return -ENXIO;
+ }
+
+ hx = devm_kzalloc(dev, sizeof(*hx), GFP_KERNEL);
+ if (!hx)
+ return -ENOMEM;
+
+ hx->client = client;
+ hx->input_dev = devm_input_allocate_device(dev);
+ if (!hx->input_dev)
+ return -ENOMEM;
+
+ hx->input_dev->name = "Himax HX852x";
+ hx->input_dev->id.bustype = BUS_I2C;
+ hx->input_dev->open = hx852x_input_open;
+ hx->input_dev->close = hx852x_input_close;
+
+ i2c_set_clientdata(client, hx);
+ input_set_drvdata(hx->input_dev, hx);
+
+ hx->supplies[0].supply = "vcca";
+ hx->supplies[1].supply = "vccd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error)
+ return dev_err_probe(dev, error, "failed to get regulators\n");
+
+ hx->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(hx->reset_gpiod))
+ return dev_err_probe(dev, PTR_ERR(hx->reset_gpiod),
+ "failed to get reset gpio\n");
+
+ error = devm_request_threaded_irq(dev, client->irq, NULL, hx852x_interrupt,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, NULL, hx);
+ if (error)
+ return dev_err_probe(dev, error, "failed to request irq %d", client->irq);
+
+ error = hx852x_read_config(hx);
+ if (error)
+ return error;
+
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_X);
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hx->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+ touchscreen_parse_properties(hx->input_dev, true, &hx->props);
+ error = hx852x_parse_properties(hx);
+ if (error)
+ return error;
+
+ hx->input_dev->keycode = hx->keycodes;
+ hx->input_dev->keycodemax = hx->keycount;
+ hx->input_dev->keycodesize = sizeof(hx->keycodes[0]);
+ for (i = 0; i < hx->keycount; i++)
+ input_set_capability(hx->input_dev, EV_KEY, hx->keycodes[i]);
+
+ error = input_mt_init_slots(hx->input_dev, hx->max_fingers,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (error)
+ return dev_err_probe(dev, error, "failed to init MT slots\n");
+
+ error = input_register_device(hx->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "failed to register input device\n");
+
+ return 0;
+}
+
+static int hx852x_suspend(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_stop(hx);
+
+ return 0;
+}
+
+static int hx852x_resume(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_start(hx);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(hx852x_pm_ops, hx852x_suspend, hx852x_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id hx852x_of_match[] = {
+ { .compatible = "himax,hx852es" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hx852x_of_match);
+#endif
+
+static struct i2c_driver hx852x_driver = {
+ .probe = hx852x_probe,
+ .driver = {
+ .name = "himax_hx852x",
+ .pm = pm_sleep_ptr(&hx852x_pm_ops),
+ .of_match_table = of_match_ptr(hx852x_of_match),
+ },
+};
+module_i2c_driver(hx852x_driver);
+
+MODULE_DESCRIPTION("Himax HX852x(ES) Touchscreen Driver");
+MODULE_AUTHOR("Jonathan Albrieux <jonathan.albrieux@gmail.com>");
+MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c
index 8f4989aba9a4..b2ff7a45b908 100644
--- a/drivers/input/touchscreen/hycon-hy46xx.c
+++ b/drivers/input/touchscreen/hycon-hy46xx.c
@@ -15,7 +15,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HY46XX_CHKSUM_CODE 0x1
#define HY46XX_FINGER_NUM 0x2
@@ -202,7 +202,7 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev,
*field = val;
}
- count = scnprintf(buf, PAGE_SIZE, "%d\n", val);
+ count = sysfs_emit(buf, "%d\n", val);
out:
mutex_unlock(&tsdata->mutex);
@@ -274,10 +274,7 @@ static struct attribute *hycon_hy46xx_attrs[] = {
&hycon_hy46xx_attr_bootloader_version.dattr.attr,
NULL
};
-
-static const struct attribute_group hycon_hy46xx_attr_group = {
- .attrs = hycon_hy46xx_attrs,
-};
+ATTRIBUTE_GROUPS(hycon_hy46xx);
static void hycon_hy46xx_get_defaults(struct device *dev, struct hycon_hy46xx_data *tsdata)
{
@@ -535,10 +532,6 @@ static int hycon_hy46xx_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &hycon_hy46xx_attr_group);
- if (error)
- return error;
-
error = input_register_device(input);
if (error)
return error;
@@ -576,11 +569,12 @@ MODULE_DEVICE_TABLE(of, hycon_hy46xx_of_match);
static struct i2c_driver hycon_hy46xx_driver = {
.driver = {
.name = "hycon_hy46xx",
+ .dev_groups = hycon_hy46xx_groups,
.of_match_table = hycon_hy46xx_of_match,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = hycon_hy46xx_id,
- .probe_new = hycon_hy46xx_probe,
+ .probe = hycon_hy46xx_probe,
};
module_i2c_driver(hycon_hy46xx_driver);
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
new file mode 100644
index 000000000000..b64d7928e18f
--- /dev/null
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for I2C connected Hynitron CST816x Series Touchscreen
+ *
+ * Copyright (C) 2025 Oleh Kuzhylnyi <kuzhylol@gmail.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/unaligned.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#define CST816X_RD_REG 0x01
+#define CST816X_NUM_KEYS 5
+
+struct cst816x_touch {
+ u8 gest;
+ u8 active;
+ u16 abs_x;
+ u16 abs_y;
+} __packed;
+
+struct cst816x_priv {
+ struct i2c_client *client;
+ struct gpio_desc *reset;
+ struct input_dev *input;
+ unsigned int keycode[CST816X_NUM_KEYS];
+ unsigned int keycodemax;
+};
+
+static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
+{
+ int count;
+ int error;
+
+ if (device_property_present(dev, "linux,keycodes")) {
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count < 0) {
+ error = count;
+ dev_err(dev, "failed to count keys: %d\n", error);
+ return error;
+ } else if (count > ARRAY_SIZE(priv->keycode)) {
+ dev_err(dev, "too many keys defined: %d\n", count);
+ return -EINVAL;
+ }
+ priv->keycodemax = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ priv->keycode,
+ priv->keycodemax);
+ if (error) {
+ dev_err(dev, "failed to read keycodes: %d\n", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
+ void *buf, size_t len)
+{
+ struct i2c_msg xfer[] = {
+ {
+ .addr = priv->client->addr,
+ .flags = 0,
+ .buf = &reg,
+ .len = sizeof(reg),
+ },
+ {
+ .addr = priv->client->addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = len,
+ },
+ };
+ int error;
+ int ret;
+
+ ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer));
+ if (ret != ARRAY_SIZE(xfer)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&priv->client->dev, "i2c rx err: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static u8 cst816x_gest_idx(u8 gest)
+{
+ u8 index;
+
+ switch (gest) {
+ case 0x01: /* Slide up gesture */
+ case 0x02: /* Slide down gesture */
+ case 0x03: /* Slide left gesture */
+ case 0x04: /* Slide right gesture */
+ index = gest;
+ break;
+ case 0x0c: /* Long press gesture */
+ default:
+ index = CST816X_NUM_KEYS;
+ break;
+ }
+
+ return index - 1;
+}
+
+static bool cst816x_process_touch(struct cst816x_priv *priv,
+ struct cst816x_touch *tch)
+{
+ if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch)))
+ return false;
+
+ tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0);
+ tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0);
+
+ dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n",
+ tch->abs_x, tch->abs_y, tch->active, tch->gest);
+
+ return true;
+}
+
+static int cst816x_register_input(struct cst816x_priv *priv)
+{
+ priv->input = devm_input_allocate_device(&priv->client->dev);
+ if (!priv->input)
+ return -ENOMEM;
+
+ priv->input->name = "Hynitron CST816x Series Touchscreen";
+ priv->input->phys = "input/ts";
+ priv->input->id.bustype = BUS_I2C;
+
+ input_set_drvdata(priv->input, priv);
+
+ input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
+ input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
+ input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
+
+ priv->input->keycode = priv->keycode;
+ priv->input->keycodesize = sizeof(priv->keycode[0]);
+ priv->input->keycodemax = priv->keycodemax;
+
+ for (int i = 0; i < priv->keycodemax; i++) {
+ if (priv->keycode[i] == KEY_RESERVED)
+ continue;
+
+ input_set_capability(priv->input, EV_KEY, priv->keycode[i]);
+ }
+
+ return input_register_device(priv->input);
+}
+
+static void cst816x_reset(struct cst816x_priv *priv)
+{
+ gpiod_set_value_cansleep(priv->reset, 1);
+ msleep(50);
+ gpiod_set_value_cansleep(priv->reset, 0);
+ msleep(100);
+}
+
+static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
+{
+ struct cst816x_priv *priv = cookie;
+ struct cst816x_touch tch;
+
+ if (!cst816x_process_touch(priv, &tch))
+ return IRQ_HANDLED;
+
+ input_report_abs(priv->input, ABS_X, tch.abs_x);
+ input_report_abs(priv->input, ABS_Y, tch.abs_y);
+
+ if (tch.gest)
+ input_report_key(priv->input,
+ priv->keycode[cst816x_gest_idx(tch.gest)],
+ tch.active);
+
+ input_report_key(priv->input, BTN_TOUCH, tch.active);
+
+ input_sync(priv->input);
+
+ return IRQ_HANDLED;
+}
+
+static int cst816x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct cst816x_priv *priv;
+ int error;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return dev_err_probe(dev, PTR_ERR(priv->reset),
+ "gpio reset request failed\n");
+
+ if (priv->reset)
+ cst816x_reset(priv);
+
+ error = cst816x_parse_keycodes(dev, priv);
+ if (error)
+ dev_warn(dev, "no gestures found in dt\n");
+
+ error = cst816x_register_input(priv);
+ if (error)
+ return dev_err_probe(dev, error, "input register failed\n");
+
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, cst816x_irq_cb, IRQF_ONESHOT,
+ dev_driver_string(dev), priv);
+ if (error)
+ return dev_err_probe(dev, error, "irq request failed\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id cst816x_id[] = {
+ { .name = "cst816s", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cst816x_id);
+
+static const struct of_device_id cst816x_of_match[] = {
+ { .compatible = "hynitron,cst816s", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cst816x_of_match);
+
+static struct i2c_driver cst816x_driver = {
+ .driver = {
+ .name = "cst816x",
+ .of_match_table = cst816x_of_match,
+ },
+ .id_table = cst816x_id,
+ .probe = cst816x_probe,
+};
+
+module_i2c_driver(cst816x_driver);
+
+MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>");
+MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c
index e86c85addb38..1d8ca90dcda6 100644
--- a/drivers/input/touchscreen/hynitron_cstxxx.c
+++ b/drivers/input/touchscreen/hynitron_cstxxx.c
@@ -22,7 +22,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Per chip data */
struct hynitron_ts_chip_data {
@@ -470,7 +470,7 @@ static const struct hynitron_ts_chip_data cst3xx_data = {
};
static const struct i2c_device_id hyn_tpd_id[] = {
- { .name = "hynitron_ts", 0 },
+ { .name = "hynitron_ts" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(i2c, hyn_tpd_id);
@@ -488,7 +488,7 @@ static struct i2c_driver hynitron_i2c_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = hyn_tpd_id,
- .probe_new = hyn_probe,
+ .probe = hyn_probe,
};
module_i2c_driver(hynitron_i2c_driver);
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index 4897fafa4204..fa38d70aded7 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -8,11 +8,11 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/sizes.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ILI2XXX_POLL_PERIOD 15
@@ -261,8 +261,8 @@ static int ili251x_read_touch_data(struct i2c_client *client, u8 *data)
if (!error && data[0] == 2) {
error = i2c_master_recv(client, data + ILI251X_DATA_SIZE1,
ILI251X_DATA_SIZE2);
- if (error >= 0 && error != ILI251X_DATA_SIZE2)
- error = -EIO;
+ if (error >= 0)
+ error = error == ILI251X_DATA_SIZE2 ? 0 : -EIO;
}
return error;
@@ -370,22 +370,33 @@ static int ili251x_firmware_update_resolution(struct device *dev)
/* The firmware update blob might have changed the resolution. */
error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs));
- if (error)
- return error;
+ if (!error) {
+ resx = le16_to_cpup((__le16 *)rs);
+ resy = le16_to_cpup((__le16 *)(rs + 2));
- resx = le16_to_cpup((__le16 *)rs);
- resy = le16_to_cpup((__le16 *)(rs + 2));
+ /* The value reported by the firmware is invalid. */
+ if (!resx || resx == 0xffff || !resy || resy == 0xffff)
+ error = -EINVAL;
+ }
- /* The value reported by the firmware is invalid. */
- if (!resx || resx == 0xffff || !resy || resy == 0xffff)
- return -EINVAL;
+ /*
+ * In case of error, the firmware might be stuck in bootloader mode,
+ * e.g. after a failed firmware update. Set maximum resolution, but
+ * do not fail to probe, so the user can re-trigger the firmware
+ * update and recover the touch controller.
+ */
+ if (error) {
+ dev_warn(dev, "Invalid resolution reported by controller.\n");
+ resx = 16384;
+ resy = 16384;
+ }
input_abs_set_max(priv->input, ABS_X, resx - 1);
input_abs_set_max(priv->input, ABS_Y, resy - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1);
input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1);
- return 0;
+ return error;
}
static ssize_t ili251x_firmware_update_firmware_version(struct device *dev)
@@ -571,14 +582,12 @@ static ssize_t ili210x_calibrate(struct device *dev,
}
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
-static int ili251x_firmware_to_buffer(const struct firmware *fw,
- u8 **buf, u16 *ac_end, u16 *df_end)
+static const u8 *ili251x_firmware_to_buffer(const struct firmware *fw,
+ u16 *ac_end, u16 *df_end)
{
const struct ihex_binrec *rec;
u32 fw_addr, fw_last_addr = 0;
u16 fw_len;
- u8 *fw_buf;
- int error;
/*
* The firmware ihex blob can never be bigger than 64 kiB, so make this
@@ -586,9 +595,9 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
* once, copy them all into this buffer at the right locations, and then
* do all operations on this linear buffer.
*/
- fw_buf = kzalloc(SZ_64K, GFP_KERNEL);
+ u8* fw_buf __free(kvfree) = kvmalloc(SZ_64K, GFP_KERNEL);
if (!fw_buf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
@@ -596,10 +605,8 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
fw_len = be16_to_cpu(rec->len);
/* The last 32 Byte firmware block can be 0xffe0 */
- if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32) {
- error = -EFBIG;
- goto err_big;
- }
+ if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32)
+ return ERR_PTR(-EFBIG);
/* Find the last address before DF start address, that is AC end */
if (fw_addr == 0xf000)
@@ -612,12 +619,8 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
/* DF end address is the last address in the firmware blob */
*df_end = fw_addr + fw_len;
- *buf = fw_buf;
- return 0;
-err_big:
- kfree(fw_buf);
- return error;
+ return_ptr(fw_buf);
}
/* Switch mode between Application and BootLoader */
@@ -680,7 +683,7 @@ static int ili251x_firmware_busy(struct i2c_client *client)
return 0;
}
-static int ili251x_firmware_write_to_ic(struct device *dev, u8 *fwbuf,
+static int ili251x_firmware_write_to_ic(struct device *dev, const u8 *fwbuf,
u16 start, u16 end, u8 dataflash)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -765,47 +768,17 @@ static void ili210x_hardware_reset(struct gpio_desc *reset_gpio)
msleep(300);
}
-static ssize_t ili210x_firmware_update_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ili210x_do_firmware_update(struct ili210x *priv,
+ const u8 *fwbuf, u16 ac_end, u16 df_end)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ili210x *priv = i2c_get_clientdata(client);
- const char *fwname = ILI251X_FW_FILENAME;
- const struct firmware *fw;
- u16 ac_end, df_end;
- u8 *fwbuf;
+ struct i2c_client *client = priv->client;
+ struct device *dev = &client->dev;
int error;
int i;
- error = request_ihex_firmware(&fw, fwname, dev);
- if (error) {
- dev_err(dev, "Failed to request firmware %s, error=%d\n",
- fwname, error);
- return error;
- }
-
- error = ili251x_firmware_to_buffer(fw, &fwbuf, &ac_end, &df_end);
- release_firmware(fw);
- if (error)
- return error;
-
- /*
- * Disable touchscreen IRQ, so that we would not get spurious touch
- * interrupt during firmware update, and so that the IRQ handler won't
- * trigger and interfere with the firmware update. There is no bit in
- * the touch controller to disable the IRQs during update, so we have
- * to do it this way here.
- */
- disable_irq(client->irq);
-
- dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
-
- ili210x_hardware_reset(priv->reset_gpio);
-
error = ili251x_firmware_reset(client);
if (error)
- goto exit;
+ return error;
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
@@ -815,7 +788,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
}
if (error)
- goto exit;
+ return error;
dev_dbg(dev, "IC is now in BootLoader mode\n");
@@ -824,7 +797,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0xf000, df_end, 1);
if (error) {
dev_err(dev, "DF firmware update failed, error=%d\n", error);
- goto exit;
+ return error;
}
dev_dbg(dev, "DataFlash firmware written\n");
@@ -832,7 +805,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0x2000, ac_end, 0);
if (error) {
dev_err(dev, "AC firmware update failed, error=%d\n", error);
- goto exit;
+ return error;
}
dev_dbg(dev, "Application firmware written\n");
@@ -845,27 +818,66 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
}
if (error)
- goto exit;
+ return error;
dev_dbg(dev, "IC is now in Application mode\n");
error = ili251x_firmware_update_cached_state(dev);
if (error)
- goto exit;
+ return error;
- error = count;
+ return 0;
+}
-exit:
- ili210x_hardware_reset(priv->reset_gpio);
- dev_dbg(dev, "Firmware update ended, error=%i\n", error);
- enable_irq(client->irq);
- kfree(fwbuf);
- return error;
+static ssize_t ili210x_firmware_update_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ili210x *priv = i2c_get_clientdata(client);
+ const char *fwname = ILI251X_FW_FILENAME;
+ u16 ac_end, df_end;
+ int error;
+
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_ihex_firmware(&fw, fwname, dev);
+ if (error) {
+ dev_err(dev, "Failed to request firmware %s, error=%d\n",
+ fwname, error);
+ return error;
+ }
+
+ const u8* fwbuf __free(kvfree) =
+ ili251x_firmware_to_buffer(fw, &ac_end, &df_end);
+ error = PTR_ERR_OR_ZERO(fwbuf);
+ if (error)
+ return error;
+
+ /*
+ * Disable touchscreen IRQ, so that we would not get spurious touch
+ * interrupt during firmware update, and so that the IRQ handler won't
+ * trigger and interfere with the firmware update. There is no bit in
+ * the touch controller to disable the IRQs during update, so we have
+ * to do it this way here.
+ */
+ scoped_guard(disable_irq, &client->irq) {
+ dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ dev_dbg(dev, "Firmware update ended, error=%i\n", error);
+ }
+
+ return error ?: count;
}
static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store);
-static struct attribute *ili210x_attributes[] = {
+static struct attribute *ili210x_attrs[] = {
&dev_attr_calibrate.attr,
&dev_attr_firmware_update.attr,
&dev_attr_firmware_version.attr,
@@ -886,17 +898,18 @@ static umode_t ili210x_attributes_visible(struct kobject *kobj,
if (attr == &dev_attr_calibrate.attr)
return priv->chip->has_calibrate_reg ? attr->mode : 0;
- /* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
+ /* Firmware/Kernel/Protocol/BootMode is implemented only for ILI251x */
if (!priv->chip->has_firmware_proto)
return 0;
return attr->mode;
}
-static const struct attribute_group ili210x_attr_group = {
- .attrs = ili210x_attributes,
+static const struct attribute_group ili210x_group = {
+ .attrs = ili210x_attrs,
.is_visible = ili210x_attributes_visible,
};
+__ATTRIBUTE_GROUPS(ili210x);
static void ili210x_power_down(void *data)
{
@@ -977,11 +990,10 @@ static int ili210x_i2c_probe(struct i2c_client *client)
if (priv->chip->has_pressure_reg)
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0);
error = ili251x_firmware_update_cached_state(dev);
- if (error) {
- dev_err(dev, "Unable to cache firmware information, err: %d\n",
- error);
- return error;
- }
+ if (error)
+ dev_warn(dev, "Unable to cache firmware information, err: %d\n",
+ error);
+
touchscreen_parse_properties(input, true, &priv->prop);
error = input_mt_init_slots(input, priv->chip->max_touches,
@@ -1003,13 +1015,6 @@ static int ili210x_i2c_probe(struct i2c_client *client)
if (error)
return error;
- error = devm_device_add_group(dev, &ili210x_attr_group);
- if (error) {
- dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
- error);
- return error;
- }
-
error = input_register_device(priv->input);
if (error) {
dev_err(dev, "Cannot register input device, err: %d\n", error);
@@ -1040,10 +1045,11 @@ MODULE_DEVICE_TABLE(of, ili210x_dt_ids);
static struct i2c_driver ili210x_ts_driver = {
.driver = {
.name = "ili210x_i2c",
+ .dev_groups = ili210x_groups,
.of_match_table = ili210x_dt_ids,
},
.id_table = ili210x_i2c_id,
- .probe_new = ili210x_i2c_probe,
+ .probe = ili210x_i2c_probe,
};
module_i2c_driver(ili210x_ts_driver);
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index e6ade3775a8a..0dd632724a00 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -15,12 +15,11 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/input/touchscreen.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ILITEK_TS_NAME "ilitek_ts"
@@ -37,6 +36,8 @@
#define ILITEK_TP_CMD_GET_MCU_VER 0x61
#define ILITEK_TP_CMD_GET_IC_MODE 0xC0
+#define ILITEK_TP_I2C_REPORT_ID 0x48
+
#define REPORT_COUNT_ADDRESS 61
#define ILITEK_SUPPORT_MAX_POINT 40
@@ -160,15 +161,19 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
error = ilitek_i2c_write_and_read(ts, NULL, 0, 0, buf, 64);
if (error) {
dev_err(dev, "get touch info failed, err:%d\n", error);
- goto err_sync_frame;
+ return error;
+ }
+
+ if (buf[0] != ILITEK_TP_I2C_REPORT_ID) {
+ dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]);
+ return -EINVAL;
}
report_max_point = buf[REPORT_COUNT_ADDRESS];
if (report_max_point > ts->max_tp) {
dev_err(dev, "FW report max point:%d > panel info. max:%d\n",
report_max_point, ts->max_tp);
- error = -EINVAL;
- goto err_sync_frame;
+ return -EINVAL;
}
count = DIV_ROUND_UP(report_max_point, packet_max_point);
@@ -178,7 +183,7 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
if (error) {
dev_err(dev, "get touch info. failed, cnt:%d, err:%d\n",
count, error);
- goto err_sync_frame;
+ return error;
}
}
@@ -203,10 +208,10 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
ilitek_touch_down(ts, id, x, y);
}
-err_sync_frame:
input_mt_sync_frame(input);
input_sync(input);
- return error;
+
+ return 0;
}
/* APIs of cmds for ILITEK Touch IC */
@@ -512,12 +517,12 @@ static ssize_t firmware_version_show(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
- return scnprintf(buf, PAGE_SIZE,
- "fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n",
- ts->firmware_ver[0], ts->firmware_ver[1],
- ts->firmware_ver[2], ts->firmware_ver[3],
- ts->firmware_ver[4], ts->firmware_ver[5],
- ts->firmware_ver[6], ts->firmware_ver[7]);
+ return sysfs_emit(buf,
+ "fw version: [%02X%02X.%02X%02X.%02X%02X.%02X%02X]\n",
+ ts->firmware_ver[0], ts->firmware_ver[1],
+ ts->firmware_ver[2], ts->firmware_ver[3],
+ ts->firmware_ver[4], ts->firmware_ver[5],
+ ts->firmware_ver[6], ts->firmware_ver[7]);
}
static DEVICE_ATTR_RO(firmware_version);
@@ -527,8 +532,8 @@ static ssize_t product_id_show(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
- return scnprintf(buf, PAGE_SIZE, "product id: [%04X], module: [%s]\n",
- ts->mcu_ver, ts->product_id);
+ return sysfs_emit(buf, "product id: [%04X], module: [%s]\n",
+ ts->mcu_ver, ts->product_id);
}
static DEVICE_ATTR_RO(product_id);
@@ -537,10 +542,7 @@ static struct attribute *ilitek_sysfs_attrs[] = {
&dev_attr_product_id.attr,
NULL
};
-
-static struct attribute_group ilitek_attrs_group = {
- .attrs = ilitek_sysfs_attrs,
-};
+ATTRIBUTE_GROUPS(ilitek_sysfs);
static int ilitek_ts_i2c_probe(struct i2c_client *client)
{
@@ -595,16 +597,10 @@ static int ilitek_ts_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(dev, &ilitek_attrs_group);
- if (error) {
- dev_err(dev, "sysfs create group failed: %d\n", error);
- return error;
- }
-
return 0;
}
-static int __maybe_unused ilitek_suspend(struct device *dev)
+static int ilitek_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
@@ -621,7 +617,7 @@ static int __maybe_unused ilitek_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused ilitek_resume(struct device *dev)
+static int ilitek_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct ilitek_ts_data *ts = i2c_get_clientdata(client);
@@ -640,11 +636,11 @@ static int __maybe_unused ilitek_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
static const struct i2c_device_id ilitek_ts_i2c_id[] = {
- { ILITEK_TS_NAME, 0 },
- { },
+ { ILITEK_TS_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id);
@@ -675,11 +671,12 @@ MODULE_DEVICE_TABLE(of, ilitek_ts_i2c_match);
static struct i2c_driver ilitek_ts_i2c_driver = {
.driver = {
.name = ILITEK_TS_NAME,
- .pm = &ilitek_pm_ops,
+ .dev_groups = ilitek_sysfs_groups,
+ .pm = pm_sleep_ptr(&ilitek_pm_ops),
.of_match_table = of_match_ptr(ilitek_ts_i2c_match),
.acpi_match_table = ACPI_PTR(ilitekts_acpi_id),
},
- .probe_new = ilitek_ts_i2c_probe,
+ .probe = ilitek_ts_i2c_probe,
.id_table = ilitek_ts_i2c_id,
};
module_i2c_driver(ilitek_ts_i2c_driver);
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index e2697e6c6d2a..3c8bbe284b73 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -11,31 +12,55 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#define IST30XX_REG_STATUS 0x20
+#define IST30XX_REG_CHIPID (0x40000000 | IST3038C_DIRECT_ACCESS)
+
+#define IST30XX_WHOAMI 0x30003000
+#define IST30XXA_WHOAMI 0x300a300a
+#define IST30XXB_WHOAMI 0x300b300b
+#define IST3038_WHOAMI 0x30383038
+
+#define IST3032C_WHOAMI 0x32c
+#define IST3038C_WHOAMI 0x38c
+#define IST3038H_WHOAMI 0x38d
+
+#define IST3038B_REG_CHIPID 0x30
+#define IST3038B_WHOAMI 0x30380b
+
#define IST3038C_HIB_ACCESS (0x800B << 16)
#define IST3038C_DIRECT_ACCESS BIT(31)
-#define IST3038C_REG_CHIPID 0x40001000
+#define IST3038C_REG_CHIPID (0x40001000 | IST3038C_DIRECT_ACCESS)
#define IST3038C_REG_HIB_BASE 0x30000100
#define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS)
#define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8)
#define IST3038C_REG_INTR_MESSAGE (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x4)
-#define IST3038C_WHOAMI 0x38c
#define IST3038C_CHIP_ON_DELAY_MS 60
#define IST3038C_I2C_RETRY_COUNT 3
#define IST3038C_MAX_FINGER_NUM 10
#define IST3038C_X_MASK GENMASK(23, 12)
-#define IST3038C_X_SHIFT 12
#define IST3038C_Y_MASK GENMASK(11, 0)
#define IST3038C_AREA_MASK GENMASK(27, 24)
-#define IST3038C_AREA_SHIFT 24
#define IST3038C_FINGER_COUNT_MASK GENMASK(15, 12)
-#define IST3038C_FINGER_COUNT_SHIFT 12
#define IST3038C_FINGER_STATUS_MASK GENMASK(9, 0)
+#define IST3032C_KEY_STATUS_MASK GENMASK(20, 16)
+
+struct imagis_properties {
+ unsigned int interrupt_msg_cmd;
+ unsigned int touch_coord_cmd;
+ unsigned int whoami_cmd;
+ unsigned int whoami_val;
+ bool protocol_b;
+ bool touch_keys_supported;
+};
struct imagis_ts {
struct i2c_client *client;
+ const struct imagis_properties *tdata;
struct input_dev *input_dev;
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
+ u32 keycodes[5];
+ int num_keycodes;
};
static int imagis_i2c_read_reg(struct imagis_ts *ts,
@@ -80,20 +105,18 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
{
struct imagis_ts *ts = dev_id;
u32 intr_message, finger_status;
- unsigned int finger_count, finger_pressed;
+ unsigned int finger_count, finger_pressed, key_pressed;
int i;
int error;
- error = imagis_i2c_read_reg(ts, IST3038C_REG_INTR_MESSAGE,
- &intr_message);
+ error = imagis_i2c_read_reg(ts, ts->tdata->interrupt_msg_cmd, &intr_message);
if (error) {
dev_err(&ts->client->dev,
"failed to read the interrupt message: %d\n", error);
goto out;
}
- finger_count = (intr_message & IST3038C_FINGER_COUNT_MASK) >>
- IST3038C_FINGER_COUNT_SHIFT;
+ finger_count = FIELD_GET(IST3038C_FINGER_COUNT_MASK, intr_message);
if (finger_count > IST3038C_MAX_FINGER_NUM) {
dev_err(&ts->client->dev,
"finger count %d is more than maximum supported\n",
@@ -101,12 +124,16 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
goto out;
}
- finger_pressed = intr_message & IST3038C_FINGER_STATUS_MASK;
+ finger_pressed = FIELD_GET(IST3038C_FINGER_STATUS_MASK, intr_message);
for (i = 0; i < finger_count; i++) {
- error = imagis_i2c_read_reg(ts,
- IST3038C_REG_TOUCH_COORD + (i * 4),
- &finger_status);
+ if (ts->tdata->protocol_b)
+ error = imagis_i2c_read_reg(ts,
+ ts->tdata->touch_coord_cmd + (i * 4),
+ &finger_status);
+ else
+ error = imagis_i2c_read_reg(ts,
+ ts->tdata->touch_coord_cmd, &finger_status);
if (error) {
dev_err(&ts->client->dev,
"failed to read coordinates for finger %d: %d\n",
@@ -118,14 +145,19 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER,
finger_pressed & BIT(i));
touchscreen_report_pos(ts->input_dev, &ts->prop,
- (finger_status & IST3038C_X_MASK) >>
- IST3038C_X_SHIFT,
- finger_status & IST3038C_Y_MASK, 1);
+ FIELD_GET(IST3038C_X_MASK, finger_status),
+ FIELD_GET(IST3038C_Y_MASK, finger_status),
+ true);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
- (finger_status & IST3038C_AREA_MASK) >>
- IST3038C_AREA_SHIFT);
+ FIELD_GET(IST3038C_AREA_MASK, finger_status));
}
+ key_pressed = FIELD_GET(IST3032C_KEY_STATUS_MASK, intr_message);
+
+ for (int i = 0; i < ts->num_keycodes; i++)
+ input_report_key(ts->input_dev, ts->keycodes[i],
+ key_pressed & BIT(i));
+
input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev);
@@ -210,7 +242,24 @@ static int imagis_init_input_dev(struct imagis_ts *ts)
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
- input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 16, 0, 0);
+ if (ts->tdata->touch_keys_supported) {
+ ts->num_keycodes = of_property_read_variable_u32_array(
+ ts->client->dev.of_node, "linux,keycodes",
+ ts->keycodes, 0, ARRAY_SIZE(ts->keycodes));
+ if (ts->num_keycodes <= 0) {
+ ts->keycodes[0] = KEY_APPSELECT;
+ ts->keycodes[1] = KEY_BACK;
+ ts->num_keycodes = 2;
+ }
+
+ input_dev->keycodemax = ts->num_keycodes;
+ input_dev->keycodesize = sizeof(ts->keycodes[0]);
+ input_dev->keycode = ts->keycodes;
+ }
+
+ for (int i = 0; i < ts->num_keycodes; i++)
+ input_set_capability(input_dev, EV_KEY, ts->keycodes[i]);
touchscreen_parse_properties(input_dev, true, &ts->prop);
if (!ts->prop.max_x || !ts->prop.max_y) {
@@ -261,6 +310,12 @@ static int imagis_probe(struct i2c_client *i2c)
ts->client = i2c;
+ ts->tdata = device_get_match_data(dev);
+ if (!ts->tdata) {
+ dev_err(dev, "missing chip data\n");
+ return -EINVAL;
+ }
+
error = imagis_init_regulators(ts);
if (error) {
dev_err(dev, "regulator init error: %d\n", error);
@@ -279,15 +334,13 @@ static int imagis_probe(struct i2c_client *i2c)
return error;
}
- error = imagis_i2c_read_reg(ts,
- IST3038C_REG_CHIPID | IST3038C_DIRECT_ACCESS,
- &chip_id);
+ error = imagis_i2c_read_reg(ts, ts->tdata->whoami_cmd, &chip_id);
if (error) {
dev_err(dev, "chip ID read failure: %d\n", error);
return error;
}
- if (chip_id != IST3038C_WHOAMI) {
+ if (chip_id != ts->tdata->whoami_val) {
dev_err(dev, "unknown chip ID: 0x%x\n", chip_id);
return -EINVAL;
}
@@ -309,7 +362,7 @@ static int imagis_probe(struct i2c_client *i2c)
return 0;
}
-static int __maybe_unused imagis_suspend(struct device *dev)
+static int imagis_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
@@ -325,7 +378,7 @@ static int __maybe_unused imagis_suspend(struct device *dev)
return retval;
}
-static int __maybe_unused imagis_resume(struct device *dev)
+static int imagis_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
@@ -341,11 +394,54 @@ static int __maybe_unused imagis_resume(struct device *dev)
return retval;
}
-static SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
#ifdef CONFIG_OF
+static const struct imagis_properties imagis_3032c_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3032C_WHOAMI,
+ .touch_keys_supported = true,
+ .protocol_b = true,
+};
+
+static const struct imagis_properties imagis_3038_data = {
+ .interrupt_msg_cmd = IST30XX_REG_STATUS,
+ .touch_coord_cmd = IST30XX_REG_STATUS,
+ .whoami_cmd = IST30XX_REG_CHIPID,
+ .whoami_val = IST3038_WHOAMI,
+ .touch_keys_supported = true,
+};
+
+static const struct imagis_properties imagis_3038b_data = {
+ .interrupt_msg_cmd = IST30XX_REG_STATUS,
+ .touch_coord_cmd = IST30XX_REG_STATUS,
+ .whoami_cmd = IST3038B_REG_CHIPID,
+ .whoami_val = IST3038B_WHOAMI,
+};
+
+static const struct imagis_properties imagis_3038c_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3038C_WHOAMI,
+ .protocol_b = true,
+};
+
+static const struct imagis_properties imagis_3038h_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3038H_WHOAMI,
+};
+
static const struct of_device_id imagis_of_match[] = {
- { .compatible = "imagis,ist3038c", },
+ { .compatible = "imagis,ist3032c", .data = &imagis_3032c_data },
+ { .compatible = "imagis,ist3038", .data = &imagis_3038_data },
+ { .compatible = "imagis,ist3038b", .data = &imagis_3038b_data },
+ { .compatible = "imagis,ist3038c", .data = &imagis_3038c_data },
+ { .compatible = "imagis,ist3038h", .data = &imagis_3038h_data },
{ },
};
MODULE_DEVICE_TABLE(of, imagis_of_match);
@@ -354,10 +450,10 @@ MODULE_DEVICE_TABLE(of, imagis_of_match);
static struct i2c_driver imagis_ts_driver = {
.driver = {
.name = "imagis-touchscreen",
- .pm = &imagis_pm_ops,
+ .pm = pm_sleep_ptr(&imagis_pm_ops),
.of_match_table = of_match_ptr(imagis_of_match),
},
- .probe_new = imagis_probe,
+ .probe = imagis_probe,
};
module_i2c_driver(imagis_ts_driver);
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 2d4facf70cdb..85f697de2b7e 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -7,6 +7,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -20,25 +21,23 @@
#include <linux/log2.h>
/* ADC configuration registers field define */
-#define ADC_AIEN (0x1 << 7)
+#define ADC_AIEN BIT(7)
+#define ADC_ADCH_MASK GENMASK(4, 0)
#define ADC_CONV_DISABLE 0x1F
-#define ADC_AVGE (0x1 << 5)
-#define ADC_CAL (0x1 << 7)
-#define ADC_CALF 0x2
-#define ADC_12BIT_MODE (0x2 << 2)
-#define ADC_CONV_MODE_MASK (0x3 << 2)
+#define ADC_AVGE BIT(5)
+#define ADC_CAL BIT(7)
+#define ADC_CALF BIT(1)
+#define ADC_CONV_MODE_MASK GENMASK(3, 2)
+#define ADC_12BIT_MODE 0x2
#define ADC_IPG_CLK 0x00
-#define ADC_INPUT_CLK_MASK 0x3
-#define ADC_CLK_DIV_8 (0x03 << 5)
-#define ADC_CLK_DIV_MASK (0x3 << 5)
-#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
-#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
-#define ADC_HARDWARE_TRIGGER (0x1 << 13)
-#define ADC_AVGS_SHIFT 14
-#define ADC_AVGS_MASK (0x3 << 14)
+#define ADC_INPUT_CLK_MASK GENMASK(1, 0)
+#define ADC_CLK_DIV_8 0x03
+#define ADC_CLK_DIV_MASK GENMASK(6, 5)
+#define ADC_SAMPLE_MODE BIT(4)
+#define ADC_HARDWARE_TRIGGER BIT(13)
+#define ADC_AVGS_MASK GENMASK(15, 14)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
-#define DISABLE_CONVERSION_INT (0x0 << 7)
/* ADC registers */
#define REG_ADC_HC0 0x00
@@ -55,7 +54,7 @@
#define ADC_TIMEOUT msecs_to_jiffies(100)
/* TSC registers */
-#define REG_TSC_BASIC_SETING 0x00
+#define REG_TSC_BASIC_SETTING 0x00
#define REG_TSC_PRE_CHARGE_TIME 0x10
#define REG_TSC_FLOW_CONTROL 0x20
#define REG_TSC_MEASURE_VALUE 0x30
@@ -65,19 +64,26 @@
#define REG_TSC_DEBUG_MODE 0x70
#define REG_TSC_DEBUG_MODE2 0x80
+/* TSC_MEASURE_VALUE register field define */
+#define X_VALUE_MASK GENMASK(27, 16)
+#define Y_VALUE_MASK GENMASK(11, 0)
+
/* TSC configuration registers field define */
-#define DETECT_4_WIRE_MODE (0x0 << 4)
-#define AUTO_MEASURE 0x1
-#define MEASURE_SIGNAL 0x1
-#define DETECT_SIGNAL (0x1 << 4)
-#define VALID_SIGNAL (0x1 << 8)
-#define MEASURE_INT_EN 0x1
-#define MEASURE_SIG_EN 0x1
-#define VALID_SIG_EN (0x1 << 8)
-#define DE_GLITCH_2 (0x2 << 29)
-#define START_SENSE (0x1 << 12)
-#define TSC_DISABLE (0x1 << 16)
+#define MEASURE_DELAY_TIME_MASK GENMASK(31, 8)
+#define DETECT_5_WIRE_MODE BIT(4)
+#define AUTO_MEASURE BIT(0)
+#define MEASURE_SIGNAL BIT(0)
+#define DETECT_SIGNAL BIT(4)
+#define VALID_SIGNAL BIT(8)
+#define MEASURE_INT_EN BIT(0)
+#define MEASURE_SIG_EN BIT(0)
+#define VALID_SIG_EN BIT(8)
+#define DE_GLITCH_MASK GENMASK(30, 29)
+#define DE_GLITCH_DEF 0x02
+#define START_SENSE BIT(12)
+#define TSC_DISABLE BIT(16)
#define DETECT_MODE 0x2
+#define STATE_MACHINE_MASK GENMASK(22, 20)
struct imx6ul_tsc {
struct device *dev;
@@ -92,6 +98,7 @@ struct imx6ul_tsc {
u32 pre_charge_time;
bool average_enable;
u32 average_select;
+ u32 de_glitch;
struct completion completion;
};
@@ -112,19 +119,20 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
- adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
- adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
- adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+ adc_cfg |= FIELD_PREP(ADC_CONV_MODE_MASK, ADC_12BIT_MODE) |
+ FIELD_PREP(ADC_INPUT_CLK_MASK, ADC_IPG_CLK);
+ adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE);
+ adc_cfg |= FIELD_PREP(ADC_CLK_DIV_MASK, ADC_CLK_DIV_8);
if (tsc->average_enable) {
adc_cfg &= ~ADC_AVGS_MASK;
- adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+ adc_cfg |= FIELD_PREP(ADC_AVGS_MASK, tsc->average_select);
}
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
/* enable calibration interrupt */
adc_hc |= ADC_AIEN;
- adc_hc |= ADC_CONV_DISABLE;
+ adc_hc |= FIELD_PREP(ADC_ADCH_MASK, ADC_CONV_DISABLE);
writel(adc_hc, tsc->adc_regs + REG_ADC_HC0);
/* start ADC calibration */
@@ -164,19 +172,21 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
{
u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
- adc_hc0 = DISABLE_CONVERSION_INT;
+ adc_hc0 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
- adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4;
+ adc_hc1 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_4);
writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1);
- adc_hc2 = DISABLE_CONVERSION_INT;
+ adc_hc2 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2);
- adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1;
+ adc_hc3 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_1);
writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3);
- adc_hc4 = DISABLE_CONVERSION_INT;
+ adc_hc4 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4);
}
@@ -188,13 +198,16 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{
u32 basic_setting = 0;
+ u32 debug_mode2;
u32 start;
- basic_setting |= tsc->measure_delay_time << 8;
- basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
- writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING);
+ basic_setting |= FIELD_PREP(MEASURE_DELAY_TIME_MASK,
+ tsc->measure_delay_time);
+ basic_setting |= AUTO_MEASURE;
+ writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING);
- writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
+ debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, tsc->de_glitch);
+ writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME);
writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN);
@@ -250,7 +263,7 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
usleep_range(200, 400);
debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
- state_machine = (debug_mode2 >> 20) & 0x7;
+ state_machine = FIELD_GET(STATE_MACHINE_MASK, debug_mode2);
} while (state_machine != DETECT_MODE);
usleep_range(200, 400);
@@ -278,8 +291,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
if (status & MEASURE_SIGNAL) {
value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE);
- x = (value >> 16) & 0x0fff;
- y = value & 0x0fff;
+ x = FIELD_GET(X_VALUE_MASK, value);
+ y = FIELD_GET(Y_VALUE_MASK, value);
/*
* In detect mode, we can get the xnur gpio value,
@@ -379,6 +392,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int tsc_irq;
int adc_irq;
u32 average_samples;
+ u32 de_glitch;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -501,6 +515,25 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return -EINVAL;
}
+ err = of_property_read_u32(np, "debounce-delay-us", &de_glitch);
+ if (err) {
+ tsc->de_glitch = DE_GLITCH_DEF;
+ } else {
+ u64 cycles;
+ unsigned long rate = clk_get_rate(tsc->tsc_clk);
+
+ cycles = DIV64_U64_ROUND_UP((u64)de_glitch * rate, USEC_PER_SEC);
+
+ if (cycles <= 0x3ff)
+ tsc->de_glitch = 3;
+ else if (cycles <= 0x7ff)
+ tsc->de_glitch = 2;
+ else if (cycles <= 0xfff)
+ tsc->de_glitch = 1;
+ else
+ tsc->de_glitch = 0;
+ }
+
err = input_register_device(tsc->input);
if (err) {
dev_err(&pdev->dev,
@@ -512,7 +545,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
+static int imx6ul_tsc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
@@ -528,7 +561,7 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
+static int imx6ul_tsc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
@@ -545,8 +578,8 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
return retval;
}
-static SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,
- imx6ul_tsc_suspend, imx6ul_tsc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,
+ imx6ul_tsc_suspend, imx6ul_tsc_resume);
static const struct of_device_id imx6ul_tsc_match[] = {
{ .compatible = "fsl,imx6ul-tsc", },
@@ -558,7 +591,7 @@ static struct platform_driver imx6ul_tsc_driver = {
.driver = {
.name = "imx6ul-tsc",
.of_match_table = imx6ul_tsc_match,
- .pm = &imx6ul_tsc_pm_ops,
+ .pm = pm_sleep_ptr(&imx6ul_tsc_pm_ops),
},
.probe = imx6ul_tsc_probe,
};
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 1d7e4c3966ce..82f7ac62a4f2 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -114,7 +114,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pinexio = kzalloc(sizeof(struct inexio), GFP_KERNEL);
+ pinexio = kzalloc(sizeof(*pinexio), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pinexio || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c
index 0eb5689fe65f..94720c41c9be 100644
--- a/drivers/input/touchscreen/ipaq-micro-ts.c
+++ b/drivers/input/touchscreen/ipaq-micro-ts.c
@@ -119,7 +119,7 @@ static int micro_ts_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused micro_ts_suspend(struct device *dev)
+static int micro_ts_suspend(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
@@ -128,7 +128,7 @@ static int __maybe_unused micro_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused micro_ts_resume(struct device *dev)
+static int micro_ts_resume(struct device *dev)
{
struct touchscreen_data *ts = dev_get_drvdata(dev);
struct input_dev *input = ts->input;
@@ -143,14 +143,13 @@ static int __maybe_unused micro_ts_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops micro_ts_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(micro_ts_suspend, micro_ts_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(micro_ts_dev_pm_ops,
+ micro_ts_suspend, micro_ts_resume);
static struct platform_driver micro_ts_device_driver = {
.driver = {
.name = "ipaq-micro-ts",
- .pm = &micro_ts_dev_pm_ops,
+ .pm = pm_sleep_ptr(&micro_ts_dev_pm_ops),
},
.probe = micro_ts_probe,
};
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index dc3137a34f35..4ebd7565ae6e 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -23,10 +23,10 @@
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_device.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define IQS5XX_FW_FILE_LEN 64
#define IQS5XX_NUM_RETRIES 10
@@ -943,12 +943,12 @@ static ssize_t fw_info_show(struct device *dev,
if (!iqs5xx->dev_id_info.bl_status)
return -ENODATA;
- return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n",
- be16_to_cpu(iqs5xx->dev_id_info.prod_num),
- be16_to_cpu(iqs5xx->dev_id_info.proj_num),
- iqs5xx->dev_id_info.major_ver,
- iqs5xx->dev_id_info.minor_ver,
- iqs5xx->exp_file[0], iqs5xx->exp_file[1]);
+ return sysfs_emit(buf, "%u.%u.%u.%u:%u.%u\n",
+ be16_to_cpu(iqs5xx->dev_id_info.prod_num),
+ be16_to_cpu(iqs5xx->dev_id_info.proj_num),
+ iqs5xx->dev_id_info.major_ver,
+ iqs5xx->dev_id_info.minor_ver,
+ iqs5xx->exp_file[0], iqs5xx->exp_file[1]);
}
static DEVICE_ATTR_WO(fw_file);
@@ -974,12 +974,13 @@ static umode_t iqs5xx_attr_is_visible(struct kobject *kobj,
return attr->mode;
}
-static const struct attribute_group iqs5xx_attr_group = {
+static const struct attribute_group iqs5xx_group = {
.is_visible = iqs5xx_attr_is_visible,
.attrs = iqs5xx_attrs,
};
+__ATTRIBUTE_GROUPS(iqs5xx);
-static int __maybe_unused iqs5xx_suspend(struct device *dev)
+static int iqs5xx_suspend(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
@@ -998,7 +999,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
return error;
}
-static int __maybe_unused iqs5xx_resume(struct device *dev)
+static int iqs5xx_resume(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
@@ -1017,7 +1018,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);
static int iqs5xx_probe(struct i2c_client *client)
{
@@ -1053,12 +1054,6 @@ static int iqs5xx_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &iqs5xx_attr_group);
- if (error) {
- dev_err(&client->dev, "Failed to add attributes: %d\n", error);
- return error;
- }
-
if (iqs5xx->input) {
error = input_register_device(iqs5xx->input);
if (error)
@@ -1089,11 +1084,12 @@ MODULE_DEVICE_TABLE(of, iqs5xx_of_match);
static struct i2c_driver iqs5xx_i2c_driver = {
.driver = {
.name = "iqs5xx",
+ .dev_groups = iqs5xx_groups,
.of_match_table = iqs5xx_of_match,
- .pm = &iqs5xx_pm,
+ .pm = pm_sleep_ptr(&iqs5xx_pm),
},
.id_table = iqs5xx_id,
- .probe_new = iqs5xx_probe,
+ .probe = iqs5xx_probe,
};
module_i2c_driver(iqs5xx_i2c_driver);
diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c
new file mode 100644
index 000000000000..c5d447ee6f53
--- /dev/null
+++ b/drivers/input/touchscreen/iqs7211.c
@@ -0,0 +1,2557 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller
+ *
+ * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
+
+#define IQS7211_PROD_NUM 0x00
+
+#define IQS7211_EVENT_MASK_ALL GENMASK(14, 8)
+#define IQS7211_EVENT_MASK_ALP BIT(13)
+#define IQS7211_EVENT_MASK_BTN BIT(12)
+#define IQS7211_EVENT_MASK_ATI BIT(11)
+#define IQS7211_EVENT_MASK_MOVE BIT(10)
+#define IQS7211_EVENT_MASK_GSTR BIT(9)
+#define IQS7211_EVENT_MODE BIT(8)
+
+#define IQS7211_COMMS_ERROR 0xEEEE
+#define IQS7211_COMMS_RETRY_MS 50
+#define IQS7211_COMMS_SLEEP_US 100
+#define IQS7211_COMMS_TIMEOUT_US (100 * USEC_PER_MSEC)
+#define IQS7211_RESET_TIMEOUT_MS 150
+#define IQS7211_START_TIMEOUT_US (1 * USEC_PER_SEC)
+
+#define IQS7211_NUM_RETRIES 5
+#define IQS7211_NUM_CRX 8
+#define IQS7211_MAX_CTX 13
+
+#define IQS7211_MAX_CONTACTS 2
+#define IQS7211_MAX_CYCLES 21
+
+/*
+ * The following delay is used during instances that must wait for the open-
+ * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C
+ * represent typical datasheet values of 4.7k and 100 nF, respectively.
+ */
+#define iqs7211_irq_wait() usleep_range(2500, 2600)
+
+enum iqs7211_dev_id {
+ IQS7210A,
+ IQS7211A,
+ IQS7211E,
+};
+
+enum iqs7211_comms_mode {
+ IQS7211_COMMS_MODE_WAIT,
+ IQS7211_COMMS_MODE_FREE,
+ IQS7211_COMMS_MODE_FORCE,
+};
+
+struct iqs7211_reg_field_desc {
+ struct list_head list;
+ u8 addr;
+ u16 mask;
+ u16 val;
+};
+
+enum iqs7211_reg_key_id {
+ IQS7211_REG_KEY_NONE,
+ IQS7211_REG_KEY_PROX,
+ IQS7211_REG_KEY_TOUCH,
+ IQS7211_REG_KEY_TAP,
+ IQS7211_REG_KEY_HOLD,
+ IQS7211_REG_KEY_PALM,
+ IQS7211_REG_KEY_AXIAL_X,
+ IQS7211_REG_KEY_AXIAL_Y,
+ IQS7211_REG_KEY_RESERVED
+};
+
+enum iqs7211_reg_grp_id {
+ IQS7211_REG_GRP_TP,
+ IQS7211_REG_GRP_BTN,
+ IQS7211_REG_GRP_ALP,
+ IQS7211_REG_GRP_SYS,
+ IQS7211_NUM_REG_GRPS
+};
+
+static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = {
+ [IQS7211_REG_GRP_TP] = "trackpad",
+ [IQS7211_REG_GRP_BTN] = "button",
+ [IQS7211_REG_GRP_ALP] = "alp",
+};
+
+static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = {
+ [IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR,
+ [IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN,
+ [IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP,
+};
+
+struct iqs7211_event_desc {
+ const char *name;
+ u16 mask;
+ u16 enable;
+ enum iqs7211_reg_grp_id reg_grp;
+ enum iqs7211_reg_key_id reg_key;
+};
+
+static const struct iqs7211_event_desc iqs7210a_kp_events[] = {
+ {
+ .mask = BIT(10),
+ .enable = BIT(13) | BIT(12),
+ .reg_grp = IQS7211_REG_GRP_ALP,
+ },
+ {
+ .name = "event-prox",
+ .mask = BIT(2),
+ .enable = BIT(5) | BIT(4),
+ .reg_grp = IQS7211_REG_GRP_BTN,
+ .reg_key = IQS7211_REG_KEY_PROX,
+ },
+ {
+ .name = "event-touch",
+ .mask = BIT(3),
+ .enable = BIT(5) | BIT(4),
+ .reg_grp = IQS7211_REG_GRP_BTN,
+ .reg_key = IQS7211_REG_KEY_TOUCH,
+ },
+ {
+ .name = "event-tap",
+ .mask = BIT(0),
+ .enable = BIT(0),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_TAP,
+ },
+ {
+ .name = "event-hold",
+ .mask = BIT(1),
+ .enable = BIT(1),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-swipe-x-neg",
+ .mask = BIT(2),
+ .enable = BIT(2),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-x-pos",
+ .mask = BIT(3),
+ .enable = BIT(3),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-y-pos",
+ .mask = BIT(4),
+ .enable = BIT(4),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+ {
+ .name = "event-swipe-y-neg",
+ .mask = BIT(5),
+ .enable = BIT(5),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+};
+
+static const struct iqs7211_event_desc iqs7211a_kp_events[] = {
+ {
+ .mask = BIT(14),
+ .reg_grp = IQS7211_REG_GRP_ALP,
+ },
+ {
+ .name = "event-tap",
+ .mask = BIT(0),
+ .enable = BIT(0),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_TAP,
+ },
+ {
+ .name = "event-hold",
+ .mask = BIT(1),
+ .enable = BIT(1),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-swipe-x-neg",
+ .mask = BIT(2),
+ .enable = BIT(2),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-x-pos",
+ .mask = BIT(3),
+ .enable = BIT(3),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-y-pos",
+ .mask = BIT(4),
+ .enable = BIT(4),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+ {
+ .name = "event-swipe-y-neg",
+ .mask = BIT(5),
+ .enable = BIT(5),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+};
+
+static const struct iqs7211_event_desc iqs7211e_kp_events[] = {
+ {
+ .mask = BIT(14),
+ .reg_grp = IQS7211_REG_GRP_ALP,
+ },
+ {
+ .name = "event-tap",
+ .mask = BIT(0),
+ .enable = BIT(0),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_TAP,
+ },
+ {
+ .name = "event-tap-double",
+ .mask = BIT(1),
+ .enable = BIT(1),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_TAP,
+ },
+ {
+ .name = "event-tap-triple",
+ .mask = BIT(2),
+ .enable = BIT(2),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_TAP,
+ },
+ {
+ .name = "event-hold",
+ .mask = BIT(3),
+ .enable = BIT(3),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-palm",
+ .mask = BIT(4),
+ .enable = BIT(4),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_PALM,
+ },
+ {
+ .name = "event-swipe-x-pos",
+ .mask = BIT(8),
+ .enable = BIT(8),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-x-neg",
+ .mask = BIT(9),
+ .enable = BIT(9),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ },
+ {
+ .name = "event-swipe-y-pos",
+ .mask = BIT(10),
+ .enable = BIT(10),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+ {
+ .name = "event-swipe-y-neg",
+ .mask = BIT(11),
+ .enable = BIT(11),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ },
+ {
+ .name = "event-swipe-x-pos-hold",
+ .mask = BIT(12),
+ .enable = BIT(12),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-swipe-x-neg-hold",
+ .mask = BIT(13),
+ .enable = BIT(13),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-swipe-y-pos-hold",
+ .mask = BIT(14),
+ .enable = BIT(14),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+ {
+ .name = "event-swipe-y-neg-hold",
+ .mask = BIT(15),
+ .enable = BIT(15),
+ .reg_grp = IQS7211_REG_GRP_TP,
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ },
+};
+
+struct iqs7211_dev_desc {
+ const char *tp_name;
+ const char *kp_name;
+ u16 prod_num;
+ u16 show_reset;
+ u16 ati_error[IQS7211_NUM_REG_GRPS];
+ u16 ati_start[IQS7211_NUM_REG_GRPS];
+ u16 suspend;
+ u16 ack_reset;
+ u16 comms_end;
+ u16 comms_req;
+ int charge_shift;
+ int info_offs;
+ int gesture_offs;
+ int contact_offs;
+ u8 sys_stat;
+ u8 sys_ctrl;
+ u8 alp_config;
+ u8 tp_config;
+ u8 exp_file;
+ u8 kp_enable[IQS7211_NUM_REG_GRPS];
+ u8 gesture_angle;
+ u8 rx_tx_map;
+ u8 cycle_alloc[2];
+ u8 cycle_limit[2];
+ const struct iqs7211_event_desc *kp_events;
+ int num_kp_events;
+ int min_crx_alp;
+ int num_ctx;
+};
+
+static const struct iqs7211_dev_desc iqs7211_devs[] = {
+ [IQS7210A] = {
+ .tp_name = "iqs7210a_trackpad",
+ .kp_name = "iqs7210a_keys",
+ .prod_num = 944,
+ .show_reset = BIT(15),
+ .ati_error = {
+ [IQS7211_REG_GRP_TP] = BIT(12),
+ [IQS7211_REG_GRP_BTN] = BIT(0),
+ [IQS7211_REG_GRP_ALP] = BIT(8),
+ },
+ .ati_start = {
+ [IQS7211_REG_GRP_TP] = BIT(13),
+ [IQS7211_REG_GRP_BTN] = BIT(1),
+ [IQS7211_REG_GRP_ALP] = BIT(9),
+ },
+ .suspend = BIT(11),
+ .ack_reset = BIT(7),
+ .comms_end = BIT(2),
+ .comms_req = BIT(1),
+ .charge_shift = 4,
+ .info_offs = 0,
+ .gesture_offs = 1,
+ .contact_offs = 4,
+ .sys_stat = 0x0A,
+ .sys_ctrl = 0x35,
+ .alp_config = 0x39,
+ .tp_config = 0x4E,
+ .exp_file = 0x57,
+ .kp_enable = {
+ [IQS7211_REG_GRP_TP] = 0x58,
+ [IQS7211_REG_GRP_BTN] = 0x37,
+ [IQS7211_REG_GRP_ALP] = 0x37,
+ },
+ .gesture_angle = 0x5F,
+ .rx_tx_map = 0x60,
+ .cycle_alloc = { 0x66, 0x75, },
+ .cycle_limit = { 10, 6, },
+ .kp_events = iqs7210a_kp_events,
+ .num_kp_events = ARRAY_SIZE(iqs7210a_kp_events),
+ .min_crx_alp = 4,
+ .num_ctx = IQS7211_MAX_CTX - 1,
+ },
+ [IQS7211A] = {
+ .tp_name = "iqs7211a_trackpad",
+ .kp_name = "iqs7211a_keys",
+ .prod_num = 763,
+ .show_reset = BIT(7),
+ .ati_error = {
+ [IQS7211_REG_GRP_TP] = BIT(3),
+ [IQS7211_REG_GRP_ALP] = BIT(5),
+ },
+ .ati_start = {
+ [IQS7211_REG_GRP_TP] = BIT(5),
+ [IQS7211_REG_GRP_ALP] = BIT(6),
+ },
+ .ack_reset = BIT(7),
+ .comms_req = BIT(4),
+ .charge_shift = 0,
+ .info_offs = 0,
+ .gesture_offs = 1,
+ .contact_offs = 4,
+ .sys_stat = 0x10,
+ .sys_ctrl = 0x50,
+ .tp_config = 0x60,
+ .alp_config = 0x72,
+ .exp_file = 0x74,
+ .kp_enable = {
+ [IQS7211_REG_GRP_TP] = 0x80,
+ },
+ .gesture_angle = 0x87,
+ .rx_tx_map = 0x90,
+ .cycle_alloc = { 0xA0, 0xB0, },
+ .cycle_limit = { 10, 8, },
+ .kp_events = iqs7211a_kp_events,
+ .num_kp_events = ARRAY_SIZE(iqs7211a_kp_events),
+ .num_ctx = IQS7211_MAX_CTX - 1,
+ },
+ [IQS7211E] = {
+ .tp_name = "iqs7211e_trackpad",
+ .kp_name = "iqs7211e_keys",
+ .prod_num = 1112,
+ .show_reset = BIT(7),
+ .ati_error = {
+ [IQS7211_REG_GRP_TP] = BIT(3),
+ [IQS7211_REG_GRP_ALP] = BIT(5),
+ },
+ .ati_start = {
+ [IQS7211_REG_GRP_TP] = BIT(5),
+ [IQS7211_REG_GRP_ALP] = BIT(6),
+ },
+ .suspend = BIT(11),
+ .ack_reset = BIT(7),
+ .comms_end = BIT(6),
+ .comms_req = BIT(4),
+ .charge_shift = 0,
+ .info_offs = 1,
+ .gesture_offs = 0,
+ .contact_offs = 2,
+ .sys_stat = 0x0E,
+ .sys_ctrl = 0x33,
+ .tp_config = 0x41,
+ .alp_config = 0x36,
+ .exp_file = 0x4A,
+ .kp_enable = {
+ [IQS7211_REG_GRP_TP] = 0x4B,
+ },
+ .gesture_angle = 0x55,
+ .rx_tx_map = 0x56,
+ .cycle_alloc = { 0x5D, 0x6C, },
+ .cycle_limit = { 10, 11, },
+ .kp_events = iqs7211e_kp_events,
+ .num_kp_events = ARRAY_SIZE(iqs7211e_kp_events),
+ .num_ctx = IQS7211_MAX_CTX,
+ },
+};
+
+struct iqs7211_prop_desc {
+ const char *name;
+ enum iqs7211_reg_key_id reg_key;
+ u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)];
+ int reg_shift;
+ int reg_width;
+ int val_pitch;
+ int val_min;
+ int val_max;
+ const char *label;
+};
+
+static const struct iqs7211_prop_desc iqs7211_props[] = {
+ {
+ .name = "azoteq,ati-frac-div-fine",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x1E,
+ [IQS7211A] = 0x30,
+ [IQS7211E] = 0x21,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x22,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x23,
+ [IQS7211A] = 0x36,
+ [IQS7211E] = 0x25,
+ },
+ },
+ .reg_shift = 9,
+ .reg_width = 5,
+ .label = "ATI fine fractional divider",
+ },
+ {
+ .name = "azoteq,ati-frac-mult-coarse",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x1E,
+ [IQS7211A] = 0x30,
+ [IQS7211E] = 0x21,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x22,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x23,
+ [IQS7211A] = 0x36,
+ [IQS7211E] = 0x25,
+ },
+ },
+ .reg_shift = 5,
+ .reg_width = 4,
+ .label = "ATI coarse fractional multiplier",
+ },
+ {
+ .name = "azoteq,ati-frac-div-coarse",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x1E,
+ [IQS7211A] = 0x30,
+ [IQS7211E] = 0x21,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x22,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x23,
+ [IQS7211A] = 0x36,
+ [IQS7211E] = 0x25,
+ },
+ },
+ .reg_shift = 0,
+ .reg_width = 5,
+ .label = "ATI coarse fractional divider",
+ },
+ {
+ .name = "azoteq,ati-comp-div",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x1F,
+ [IQS7211E] = 0x22,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x24,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7211E] = 0x26,
+ },
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_max = 31,
+ .label = "ATI compensation divider",
+ },
+ {
+ .name = "azoteq,ati-comp-div",
+ .reg_addr = {
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x24,
+ },
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_max = 31,
+ .label = "ATI compensation divider",
+ },
+ {
+ .name = "azoteq,ati-comp-div",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7211A] = 0x31,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7211A] = 0x37,
+ },
+ },
+ .val_max = 31,
+ .label = "ATI compensation divider",
+ },
+ {
+ .name = "azoteq,ati-target",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x20,
+ [IQS7211A] = 0x32,
+ [IQS7211E] = 0x23,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x27,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x28,
+ [IQS7211A] = 0x38,
+ [IQS7211E] = 0x27,
+ },
+ },
+ .label = "ATI target",
+ },
+ {
+ .name = "azoteq,ati-base",
+ .reg_addr[IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x26,
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 8,
+ .label = "ATI base",
+ },
+ {
+ .name = "azoteq,ati-base",
+ .reg_addr[IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x26,
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_pitch = 8,
+ .label = "ATI base",
+ },
+ {
+ .name = "azoteq,rate-active-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x29,
+ [IQS7211A] = 0x40,
+ [IQS7211E] = 0x28,
+ },
+ .label = "active mode report rate",
+ },
+ {
+ .name = "azoteq,rate-touch-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2A,
+ [IQS7211A] = 0x41,
+ [IQS7211E] = 0x29,
+ },
+ .label = "idle-touch mode report rate",
+ },
+ {
+ .name = "azoteq,rate-idle-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2B,
+ [IQS7211A] = 0x42,
+ [IQS7211E] = 0x2A,
+ },
+ .label = "idle mode report rate",
+ },
+ {
+ .name = "azoteq,rate-lp1-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2C,
+ [IQS7211A] = 0x43,
+ [IQS7211E] = 0x2B,
+ },
+ .label = "low-power mode 1 report rate",
+ },
+ {
+ .name = "azoteq,rate-lp2-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2D,
+ [IQS7211A] = 0x44,
+ [IQS7211E] = 0x2C,
+ },
+ .label = "low-power mode 2 report rate",
+ },
+ {
+ .name = "azoteq,timeout-active-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2E,
+ [IQS7211A] = 0x45,
+ [IQS7211E] = 0x2D,
+ },
+ .val_pitch = 1000,
+ .label = "active mode timeout",
+ },
+ {
+ .name = "azoteq,timeout-touch-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x2F,
+ [IQS7211A] = 0x46,
+ [IQS7211E] = 0x2E,
+ },
+ .val_pitch = 1000,
+ .label = "idle-touch mode timeout",
+ },
+ {
+ .name = "azoteq,timeout-idle-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x30,
+ [IQS7211A] = 0x47,
+ [IQS7211E] = 0x2F,
+ },
+ .val_pitch = 1000,
+ .label = "idle mode timeout",
+ },
+ {
+ .name = "azoteq,timeout-lp1-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x31,
+ [IQS7211A] = 0x48,
+ [IQS7211E] = 0x30,
+ },
+ .val_pitch = 1000,
+ .label = "low-power mode 1 timeout",
+ },
+ {
+ .name = "azoteq,timeout-lp2-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x32,
+ [IQS7211E] = 0x31,
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 1000,
+ .val_max = 60000,
+ .label = "trackpad reference value update rate",
+ },
+ {
+ .name = "azoteq,timeout-lp2-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7211A] = 0x49,
+ },
+ .val_pitch = 1000,
+ .val_max = 60000,
+ .label = "trackpad reference value update rate",
+ },
+ {
+ .name = "azoteq,timeout-ati-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x32,
+ [IQS7211E] = 0x31,
+ },
+ .reg_width = 8,
+ .val_pitch = 1000,
+ .val_max = 60000,
+ .label = "ATI error timeout",
+ },
+ {
+ .name = "azoteq,timeout-ati-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7211A] = 0x35,
+ },
+ .val_pitch = 1000,
+ .val_max = 60000,
+ .label = "ATI error timeout",
+ },
+ {
+ .name = "azoteq,timeout-comms-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x33,
+ [IQS7211A] = 0x4A,
+ [IQS7211E] = 0x32,
+ },
+ .label = "communication timeout",
+ },
+ {
+ .name = "azoteq,timeout-press-ms",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x34,
+ },
+ .reg_width = 8,
+ .val_pitch = 1000,
+ .val_max = 60000,
+ .label = "press timeout",
+ },
+ {
+ .name = "azoteq,ati-mode",
+ .reg_addr[IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x37,
+ },
+ .reg_shift = 15,
+ .reg_width = 1,
+ .label = "ATI mode",
+ },
+ {
+ .name = "azoteq,ati-mode",
+ .reg_addr[IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x37,
+ },
+ .reg_shift = 7,
+ .reg_width = 1,
+ .label = "ATI mode",
+ },
+ {
+ .name = "azoteq,sense-mode",
+ .reg_addr[IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x37,
+ [IQS7211A] = 0x72,
+ [IQS7211E] = 0x36,
+ },
+ .reg_shift = 8,
+ .reg_width = 1,
+ .label = "sensing mode",
+ },
+ {
+ .name = "azoteq,sense-mode",
+ .reg_addr[IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x37,
+ },
+ .reg_shift = 0,
+ .reg_width = 2,
+ .val_max = 2,
+ .label = "sensing mode",
+ },
+ {
+ .name = "azoteq,fosc-freq",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x38,
+ [IQS7211A] = 0x52,
+ [IQS7211E] = 0x35,
+ },
+ .reg_shift = 4,
+ .reg_width = 1,
+ .label = "core clock frequency selection",
+ },
+ {
+ .name = "azoteq,fosc-trim",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x38,
+ [IQS7211A] = 0x52,
+ [IQS7211E] = 0x35,
+ },
+ .reg_shift = 0,
+ .reg_width = 4,
+ .label = "core clock frequency trim",
+ },
+ {
+ .name = "azoteq,touch-exit",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x3B,
+ [IQS7211A] = 0x53,
+ [IQS7211E] = 0x38,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x3E,
+ },
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "touch exit factor",
+ },
+ {
+ .name = "azoteq,touch-enter",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x3B,
+ [IQS7211A] = 0x53,
+ [IQS7211E] = 0x38,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x3E,
+ },
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "touch entrance factor",
+ },
+ {
+ .name = "azoteq,thresh",
+ .reg_addr = {
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x3C,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x3D,
+ [IQS7211A] = 0x54,
+ [IQS7211E] = 0x39,
+ },
+ },
+ .label = "threshold",
+ },
+ {
+ .name = "azoteq,debounce-exit",
+ .reg_addr = {
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x3F,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x40,
+ [IQS7211A] = 0x56,
+ [IQS7211E] = 0x3A,
+ },
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "debounce exit factor",
+ },
+ {
+ .name = "azoteq,debounce-enter",
+ .reg_addr = {
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x3F,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x40,
+ [IQS7211A] = 0x56,
+ [IQS7211E] = 0x3A,
+ },
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "debounce entrance factor",
+ },
+ {
+ .name = "azoteq,conv-frac",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x48,
+ [IQS7211A] = 0x58,
+ [IQS7211E] = 0x3D,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x49,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x4A,
+ [IQS7211A] = 0x59,
+ [IQS7211E] = 0x3E,
+ },
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "conversion frequency fractional divider",
+ },
+ {
+ .name = "azoteq,conv-period",
+ .reg_addr = {
+ [IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x48,
+ [IQS7211A] = 0x58,
+ [IQS7211E] = 0x3D,
+ },
+ [IQS7211_REG_GRP_BTN] = {
+ [IQS7210A] = 0x49,
+ },
+ [IQS7211_REG_GRP_ALP] = {
+ [IQS7210A] = 0x4A,
+ [IQS7211A] = 0x59,
+ [IQS7211E] = 0x3E,
+ },
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "conversion period",
+ },
+ {
+ .name = "azoteq,thresh",
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x55,
+ [IQS7211A] = 0x67,
+ [IQS7211E] = 0x48,
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "threshold",
+ },
+ {
+ .name = "azoteq,contact-split",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x55,
+ [IQS7211A] = 0x67,
+ [IQS7211E] = 0x48,
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "contact split factor",
+ },
+ {
+ .name = "azoteq,trim-x",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x56,
+ [IQS7211E] = 0x49,
+ },
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "horizontal trim width",
+ },
+ {
+ .name = "azoteq,trim-x",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7211A] = 0x68,
+ },
+ .label = "horizontal trim width",
+ },
+ {
+ .name = "azoteq,trim-y",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7210A] = 0x56,
+ [IQS7211E] = 0x49,
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "vertical trim height",
+ },
+ {
+ .name = "azoteq,trim-y",
+ .reg_addr[IQS7211_REG_GRP_SYS] = {
+ [IQS7211A] = 0x69,
+ },
+ .label = "vertical trim height",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_key = IQS7211_REG_KEY_TAP,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x59,
+ [IQS7211A] = 0x81,
+ [IQS7211E] = 0x4C,
+ },
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-mid-ms",
+ .reg_key = IQS7211_REG_KEY_TAP,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7211E] = 0x4D,
+ },
+ .label = "repeated gesture time",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_key = IQS7211_REG_KEY_TAP,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5A,
+ [IQS7211A] = 0x82,
+ [IQS7211E] = 0x4E,
+ },
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5A,
+ [IQS7211A] = 0x82,
+ [IQS7211E] = 0x4E,
+ },
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-min-ms",
+ .reg_key = IQS7211_REG_KEY_HOLD,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5B,
+ [IQS7211A] = 0x83,
+ [IQS7211E] = 0x4F,
+ },
+ .label = "minimum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5C,
+ [IQS7211A] = 0x84,
+ [IQS7211E] = 0x50,
+ },
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5C,
+ [IQS7211A] = 0x84,
+ [IQS7211E] = 0x50,
+ },
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5D,
+ [IQS7211A] = 0x85,
+ [IQS7211E] = 0x51,
+ },
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7210A] = 0x5E,
+ [IQS7211A] = 0x86,
+ [IQS7211E] = 0x52,
+ },
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist-rep",
+ .reg_key = IQS7211_REG_KEY_AXIAL_X,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7211E] = 0x53,
+ },
+ .label = "repeated gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist-rep",
+ .reg_key = IQS7211_REG_KEY_AXIAL_Y,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7211E] = 0x54,
+ },
+ .label = "repeated gesture distance",
+ },
+ {
+ .name = "azoteq,thresh",
+ .reg_key = IQS7211_REG_KEY_PALM,
+ .reg_addr[IQS7211_REG_GRP_TP] = {
+ [IQS7211E] = 0x55,
+ },
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_max = 42,
+ .label = "threshold",
+ },
+};
+
+static const u8 iqs7211_gesture_angle[] = {
+ 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x06, 0x07, 0x08,
+ 0x09, 0x0A, 0x0B, 0x0C,
+ 0x0E, 0x0F, 0x10, 0x11,
+ 0x12, 0x14, 0x15, 0x16,
+ 0x17, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1E, 0x1F, 0x21,
+ 0x22, 0x23, 0x25, 0x26,
+ 0x28, 0x2A, 0x2B, 0x2D,
+ 0x2E, 0x30, 0x32, 0x34,
+ 0x36, 0x38, 0x3A, 0x3C,
+ 0x3E, 0x40, 0x42, 0x45,
+ 0x47, 0x4A, 0x4C, 0x4F,
+ 0x52, 0x55, 0x58, 0x5B,
+ 0x5F, 0x63, 0x66, 0x6B,
+ 0x6F, 0x73, 0x78, 0x7E,
+ 0x83, 0x89, 0x90, 0x97,
+ 0x9E, 0xA7, 0xB0, 0xBA,
+ 0xC5, 0xD1, 0xDF, 0xEF,
+};
+
+struct iqs7211_ver_info {
+ __le16 prod_num;
+ __le16 major;
+ __le16 minor;
+ __le32 patch;
+} __packed;
+
+struct iqs7211_touch_data {
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 pressure;
+ __le16 area;
+} __packed;
+
+struct iqs7211_tp_config {
+ u8 tp_settings;
+ u8 total_rx;
+ u8 total_tx;
+ u8 num_contacts;
+ __le16 max_x;
+ __le16 max_y;
+} __packed;
+
+struct iqs7211_private {
+ const struct iqs7211_dev_desc *dev_desc;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *irq_gpio;
+ struct i2c_client *client;
+ struct input_dev *tp_idev;
+ struct input_dev *kp_idev;
+ struct iqs7211_ver_info ver_info;
+ struct iqs7211_tp_config tp_config;
+ struct touchscreen_properties prop;
+ struct list_head reg_field_head;
+ enum iqs7211_comms_mode comms_init;
+ enum iqs7211_comms_mode comms_mode;
+ unsigned int num_contacts;
+ unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)];
+ u8 rx_tx_map[IQS7211_MAX_CTX + 1];
+ u8 cycle_alloc[2][33];
+ u8 exp_file[2];
+ u16 event_mask;
+ u16 ati_start;
+ u16 gesture_cache;
+};
+
+static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us)
+{
+ int error, val;
+
+ error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio,
+ val, val, IQS7211_COMMS_SLEEP_US, timeout_us);
+
+ return val < 0 ? val : error;
+}
+
+static int iqs7211_hard_reset(struct iqs7211_private *iqs7211)
+{
+ if (!iqs7211->reset_gpio)
+ return 0;
+
+ gpiod_set_value_cansleep(iqs7211->reset_gpio, 1);
+
+ /*
+ * The following delay ensures the shared RDY/MCLR pin is sampled in
+ * between periodic assertions by the device and assumes the default
+ * communication timeout has not been overwritten in OTP memory.
+ */
+ if (iqs7211->reset_gpio == iqs7211->irq_gpio)
+ msleep(IQS7211_RESET_TIMEOUT_MS);
+ else
+ usleep_range(1000, 1100);
+
+ gpiod_set_value_cansleep(iqs7211->reset_gpio, 0);
+ if (iqs7211->reset_gpio == iqs7211->irq_gpio)
+ iqs7211_irq_wait();
+
+ return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
+}
+
+static int iqs7211_force_comms(struct iqs7211_private *iqs7211)
+{
+ u8 msg_buf[] = { 0xFF, };
+ int ret;
+
+ switch (iqs7211->comms_mode) {
+ case IQS7211_COMMS_MODE_WAIT:
+ return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US);
+
+ case IQS7211_COMMS_MODE_FREE:
+ return 0;
+
+ case IQS7211_COMMS_MODE_FORCE:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * The device cannot communicate until it asserts its interrupt (RDY)
+ * pin. Attempts to do so while RDY is deasserted return an ACK; how-
+ * ever all write data is ignored, and all read data returns 0xEE.
+ *
+ * Unsolicited communication must be preceded by a special force com-
+ * munication command, after which the device eventually asserts its
+ * RDY pin and agrees to communicate.
+ *
+ * Regardless of whether communication is forced or the result of an
+ * interrupt, the device automatically deasserts its RDY pin once it
+ * detects an I2C stop condition, or a timeout expires.
+ */
+ ret = gpiod_get_value_cansleep(iqs7211->irq_gpio);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ return 0;
+
+ ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf));
+ if (ret < (int)sizeof(msg_buf)) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ msleep(IQS7211_COMMS_RETRY_MS);
+ return ret;
+ }
+
+ iqs7211_irq_wait();
+
+ return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US);
+}
+
+static int iqs7211_read_burst(struct iqs7211_private *iqs7211,
+ u8 reg, void *val, u16 val_len)
+{
+ int ret, i;
+ struct i2c_client *client = iqs7211->client;
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(reg),
+ .buf = &reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = val_len,
+ .buf = (u8 *)val,
+ },
+ };
+
+ /*
+ * The following loop protects against an edge case in which the RDY
+ * pin is automatically deasserted just as the read is initiated. In
+ * that case, the read must be retried using forced communication.
+ */
+ for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
+ ret = iqs7211_force_comms(iqs7211);
+ if (ret < 0)
+ continue;
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret < (int)ARRAY_SIZE(msg)) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ msleep(IQS7211_COMMS_RETRY_MS);
+ continue;
+ }
+
+ if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) {
+ ret = -ENODATA;
+ continue;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ iqs7211_irq_wait();
+
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Failed to read from address 0x%02X: %d\n", reg, ret);
+
+ return ret;
+}
+
+static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val)
+{
+ __le16 val_buf;
+ int error;
+
+ error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
+ if (error)
+ return error;
+
+ *val = le16_to_cpu(val_buf);
+
+ return 0;
+}
+
+static int iqs7211_write_burst(struct iqs7211_private *iqs7211,
+ u8 reg, const void *val, u16 val_len)
+{
+ int msg_len = sizeof(reg) + val_len;
+ int ret, i;
+ struct i2c_client *client = iqs7211->client;
+ u8 *msg_buf;
+
+ msg_buf = kzalloc(msg_len, GFP_KERNEL);
+ if (!msg_buf)
+ return -ENOMEM;
+
+ *msg_buf = reg;
+ memcpy(msg_buf + sizeof(reg), val, val_len);
+
+ /*
+ * The following loop protects against an edge case in which the RDY
+ * pin is automatically asserted just before the force communication
+ * command is sent.
+ *
+ * In that case, the subsequent I2C stop condition tricks the device
+ * into preemptively deasserting the RDY pin and the command must be
+ * sent again.
+ */
+ for (i = 0; i < IQS7211_NUM_RETRIES; i++) {
+ ret = iqs7211_force_comms(iqs7211);
+ if (ret < 0)
+ continue;
+
+ ret = i2c_master_send(client, msg_buf, msg_len);
+ if (ret < msg_len) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ msleep(IQS7211_COMMS_RETRY_MS);
+ continue;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ kfree(msg_buf);
+
+ iqs7211_irq_wait();
+
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Failed to write to address 0x%02X: %d\n", reg, ret);
+
+ return ret;
+}
+
+static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val)
+{
+ __le16 val_buf = cpu_to_le16(val);
+
+ return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf));
+}
+
+static int iqs7211_start_comms(struct iqs7211_private *iqs7211)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ bool forced_comms;
+ unsigned int val;
+ u16 comms_setup;
+ int error;
+
+ /*
+ * Until forced communication can be enabled, the host must wait for a
+ * communication window each time it intends to elicit a response from
+ * the device.
+ *
+ * Forced communication is not necessary, however, if the host adapter
+ * can support clock stretching. In that case, the device freely clock
+ * stretches until all pending conversions are complete.
+ */
+ forced_comms = device_property_present(&client->dev,
+ "azoteq,forced-comms");
+
+ error = device_property_read_u32(&client->dev,
+ "azoteq,forced-comms-default", &val);
+ if (error == -EINVAL) {
+ iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT;
+ } else if (error) {
+ dev_err(&client->dev,
+ "Failed to read default communication mode: %d\n",
+ error);
+ return error;
+ } else if (val) {
+ iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE
+ : IQS7211_COMMS_MODE_WAIT;
+ } else {
+ iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT
+ : IQS7211_COMMS_MODE_FREE;
+ }
+
+ iqs7211->comms_mode = iqs7211->comms_init;
+
+ error = iqs7211_hard_reset(iqs7211);
+ if (error) {
+ dev_err(&client->dev, "Failed to reset device: %d\n", error);
+ return error;
+ }
+
+ error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM,
+ &iqs7211->ver_info,
+ sizeof(iqs7211->ver_info));
+ if (error)
+ return error;
+
+ if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) {
+ dev_err(&client->dev, "Invalid product number: %u\n",
+ le16_to_cpu(iqs7211->ver_info.prod_num));
+ return -EINVAL;
+ }
+
+ error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1,
+ &comms_setup);
+ if (error)
+ return error;
+
+ if (forced_comms)
+ comms_setup |= dev_desc->comms_req;
+ else
+ comms_setup &= ~dev_desc->comms_req;
+
+ error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+ comms_setup | dev_desc->comms_end);
+ if (error)
+ return error;
+
+ if (forced_comms)
+ iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
+ else
+ iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
+
+ error = iqs7211_read_burst(iqs7211, dev_desc->exp_file,
+ iqs7211->exp_file,
+ sizeof(iqs7211->exp_file));
+ if (error)
+ return error;
+
+ error = iqs7211_read_burst(iqs7211, dev_desc->tp_config,
+ &iqs7211->tp_config,
+ sizeof(iqs7211->tp_config));
+ if (error)
+ return error;
+
+ error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+ comms_setup);
+ if (error)
+ return error;
+
+ iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL;
+ iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE);
+
+ return 0;
+}
+
+static int iqs7211_init_device(struct iqs7211_private *iqs7211)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct iqs7211_reg_field_desc *reg_field;
+ __le16 sys_ctrl[] = {
+ cpu_to_le16(dev_desc->ack_reset),
+ cpu_to_le16(iqs7211->event_mask),
+ };
+ int error, i;
+
+ /*
+ * Acknowledge reset before writing any registers in case the device
+ * suffers a spurious reset during initialization. The communication
+ * mode is configured at this time as well.
+ */
+ error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+ sizeof(sys_ctrl));
+ if (error)
+ return error;
+
+ if (iqs7211->event_mask & dev_desc->comms_req)
+ iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE;
+ else
+ iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE;
+
+ /*
+ * Take advantage of the stop-bit disable function, if available, to
+ * save the trouble of having to reopen a communication window after
+ * each read or write.
+ */
+ error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1,
+ iqs7211->event_mask | dev_desc->comms_end);
+ if (error)
+ return error;
+
+ list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
+ u16 new_val = reg_field->val;
+
+ if (reg_field->mask < U16_MAX) {
+ u16 old_val;
+
+ error = iqs7211_read_word(iqs7211, reg_field->addr,
+ &old_val);
+ if (error)
+ return error;
+
+ new_val = old_val & ~reg_field->mask;
+ new_val |= reg_field->val;
+
+ if (new_val == old_val)
+ continue;
+ }
+
+ error = iqs7211_write_word(iqs7211, reg_field->addr, new_val);
+ if (error)
+ return error;
+ }
+
+ error = iqs7211_write_burst(iqs7211, dev_desc->tp_config,
+ &iqs7211->tp_config,
+ sizeof(iqs7211->tp_config));
+ if (error)
+ return error;
+
+ if (**iqs7211->cycle_alloc) {
+ error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map,
+ &iqs7211->rx_tx_map,
+ dev_desc->num_ctx);
+ if (error)
+ return error;
+
+ for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) {
+ error = iqs7211_write_burst(iqs7211,
+ dev_desc->cycle_alloc[i],
+ iqs7211->cycle_alloc[i],
+ dev_desc->cycle_limit[i] * 3);
+ if (error)
+ return error;
+ }
+ }
+
+ *sys_ctrl = cpu_to_le16(iqs7211->ati_start);
+
+ return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+ sizeof(sys_ctrl));
+}
+
+static int iqs7211_add_field(struct iqs7211_private *iqs7211,
+ struct iqs7211_reg_field_desc new_field)
+{
+ struct i2c_client *client = iqs7211->client;
+ struct iqs7211_reg_field_desc *reg_field;
+
+ if (!new_field.addr)
+ return 0;
+
+ list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) {
+ if (reg_field->addr != new_field.addr)
+ continue;
+
+ reg_field->mask |= new_field.mask;
+ reg_field->val |= new_field.val;
+ return 0;
+ }
+
+ reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL);
+ if (!reg_field)
+ return -ENOMEM;
+
+ reg_field->addr = new_field.addr;
+ reg_field->mask = new_field.mask;
+ reg_field->val = new_field.val;
+
+ list_add(&reg_field->list, &iqs7211->reg_field_head);
+
+ return 0;
+}
+
+static int iqs7211_parse_props(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *reg_grp_node,
+ enum iqs7211_reg_grp_id reg_grp,
+ enum iqs7211_reg_key_id reg_key)
+{
+ struct i2c_client *client = iqs7211->client;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) {
+ const char *name = iqs7211_props[i].name;
+ u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp]
+ [iqs7211->dev_desc -
+ iqs7211_devs];
+ int reg_shift = iqs7211_props[i].reg_shift;
+ int reg_width = iqs7211_props[i].reg_width ? : 16;
+ int val_pitch = iqs7211_props[i].val_pitch ? : 1;
+ int val_min = iqs7211_props[i].val_min;
+ int val_max = iqs7211_props[i].val_max;
+ const char *label = iqs7211_props[i].label ? : name;
+ struct iqs7211_reg_field_desc reg_field;
+ unsigned int val;
+ int error;
+
+ if (iqs7211_props[i].reg_key != reg_key)
+ continue;
+
+ if (!reg_addr)
+ continue;
+
+ error = fwnode_property_read_u32(reg_grp_node, name, &val);
+ if (error == -EINVAL) {
+ continue;
+ } else if (error) {
+ dev_err(&client->dev, "Failed to read %s %s: %d\n",
+ fwnode_get_name(reg_grp_node), label, error);
+ return error;
+ }
+
+ if (!val_max)
+ val_max = GENMASK(reg_width - 1, 0) * val_pitch;
+
+ if (val < val_min || val > val_max) {
+ dev_err(&client->dev, "Invalid %s: %u\n", label, val);
+ return -EINVAL;
+ }
+
+ reg_field.addr = reg_addr;
+ reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift);
+ reg_field.val = val / val_pitch << reg_shift;
+
+ error = iqs7211_add_field(iqs7211, reg_field);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int iqs7211_parse_event(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *event_node,
+ enum iqs7211_reg_grp_id reg_grp,
+ enum iqs7211_reg_key_id reg_key,
+ unsigned int *event_code)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ struct iqs7211_reg_field_desc reg_field;
+ unsigned int val;
+ int error;
+
+ error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key);
+ if (error)
+ return error;
+
+ if (reg_key == IQS7211_REG_KEY_AXIAL_X ||
+ reg_key == IQS7211_REG_KEY_AXIAL_Y) {
+ error = fwnode_property_read_u32(event_node,
+ "azoteq,gesture-angle", &val);
+ if (!error) {
+ if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) {
+ dev_err(&client->dev,
+ "Invalid %s gesture angle: %u\n",
+ fwnode_get_name(event_node), val);
+ return -EINVAL;
+ }
+
+ reg_field.addr = dev_desc->gesture_angle;
+ reg_field.mask = U8_MAX;
+ reg_field.val = iqs7211_gesture_angle[val];
+
+ error = iqs7211_add_field(iqs7211, reg_field);
+ if (error)
+ return error;
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev,
+ "Failed to read %s gesture angle: %d\n",
+ fwnode_get_name(event_node), error);
+ return error;
+ }
+ }
+
+ error = fwnode_property_read_u32(event_node, "linux,code", event_code);
+ if (error == -EINVAL)
+ error = 0;
+ else if (error)
+ dev_err(&client->dev, "Failed to read %s code: %d\n",
+ fwnode_get_name(event_node), error);
+
+ return error;
+}
+
+static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *tp_node)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1];
+ int error, count, i, j, k, cycle_start;
+ unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2];
+ u8 total_rx = iqs7211->tp_config.total_rx;
+ u8 total_tx = iqs7211->tp_config.total_tx;
+
+ for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++)
+ *(cycle_alloc[0] + i) = U8_MAX;
+
+ count = fwnode_property_count_u32(tp_node, "azoteq,channel-select");
+ if (count == -EINVAL) {
+ /*
+ * Assign each sensing cycle's slots (0 and 1) to a channel,
+ * defined as the intersection between two CRx and CTx pins.
+ * A channel assignment of 255 means the slot is unused.
+ */
+ for (i = 0, cycle_start = 0; i < total_tx; i++) {
+ int cycle_stop = 0;
+
+ for (j = 0; j < total_rx; j++) {
+ /*
+ * Channels formed by CRx0-3 and CRx4-7 are
+ * bound to slots 0 and 1, respectively.
+ */
+ int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1;
+ int chan = i * total_rx + j;
+
+ for (k = cycle_start; k < num_cycles; k++) {
+ if (cycle_alloc[k][slot] < U8_MAX)
+ continue;
+
+ cycle_alloc[k][slot] = chan;
+ break;
+ }
+
+ if (k < num_cycles) {
+ cycle_stop = max(k, cycle_stop);
+ continue;
+ }
+
+ dev_err(&client->dev,
+ "Insufficient number of cycles\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Sensing cycles cannot straddle more than one CTx
+ * pin. As such, the next row's starting cycle must
+ * be greater than the previous row's highest cycle.
+ */
+ cycle_start = cycle_stop + 1;
+ }
+ } else if (count < 0) {
+ dev_err(&client->dev, "Failed to count channels: %d\n", count);
+ return count;
+ } else if (count > num_cycles * 2) {
+ dev_err(&client->dev, "Insufficient number of cycles\n");
+ return -EINVAL;
+ } else if (count > 0) {
+ error = fwnode_property_read_u32_array(tp_node,
+ "azoteq,channel-select",
+ cycle_alloc[0], count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read channels: %d\n",
+ error);
+ return error;
+ }
+
+ for (i = 0; i < count; i++) {
+ int chan = *(cycle_alloc[0] + i);
+
+ if (chan == U8_MAX)
+ continue;
+
+ if (chan >= total_rx * total_tx) {
+ dev_err(&client->dev, "Invalid channel: %d\n",
+ chan);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < count; j++) {
+ if (j == i || *(cycle_alloc[0] + j) != chan)
+ continue;
+
+ dev_err(&client->dev, "Duplicate channel: %d\n",
+ chan);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /*
+ * Once the raw channel assignments have been derived, they must be
+ * packed according to the device's register map.
+ */
+ for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) {
+ int offs = 0;
+
+ for (j = cycle_start;
+ j < cycle_start + dev_desc->cycle_limit[i]; j++) {
+ iqs7211->cycle_alloc[i][offs++] = 0x05;
+ iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0];
+ iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1];
+ }
+
+ cycle_start += dev_desc->cycle_limit[i];
+ }
+
+ return 0;
+}
+
+static int iqs7211_parse_tp(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *tp_node)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ unsigned int pins[IQS7211_MAX_CTX];
+ int error, count, i, j;
+
+ count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable");
+ if (count == -EINVAL) {
+ return 0;
+ } else if (count < 0) {
+ dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
+ return count;
+ } else if (count > IQS7211_NUM_CRX) {
+ dev_err(&client->dev, "Invalid number of CRx pins\n");
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read CRx pins: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (pins[i] >= IQS7211_NUM_CRX) {
+ dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]);
+ return -EINVAL;
+ }
+
+ iqs7211->rx_tx_map[i] = pins[i];
+ }
+
+ iqs7211->tp_config.total_rx = count;
+
+ count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable");
+ if (count < 0) {
+ dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
+ return count;
+ } else if (count > dev_desc->num_ctx) {
+ dev_err(&client->dev, "Invalid number of CTx pins\n");
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read CTx pins: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (pins[i] >= dev_desc->num_ctx) {
+ dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]);
+ return -EINVAL;
+ }
+
+ for (j = 0; j < iqs7211->tp_config.total_rx; j++) {
+ if (iqs7211->rx_tx_map[j] != pins[i])
+ continue;
+
+ dev_err(&client->dev, "Conflicting CTx pin: %u\n",
+ pins[i]);
+ return -EINVAL;
+ }
+
+ iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i];
+ }
+
+ iqs7211->tp_config.total_tx = count;
+
+ return iqs7211_parse_cycles(iqs7211, tp_node);
+}
+
+static int iqs7211_parse_alp(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *alp_node)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ struct iqs7211_reg_field_desc reg_field;
+ int error, count, i;
+
+ count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable");
+ if (count < 0 && count != -EINVAL) {
+ dev_err(&client->dev, "Failed to count CRx pins: %d\n", count);
+ return count;
+ } else if (count > IQS7211_NUM_CRX) {
+ dev_err(&client->dev, "Invalid number of CRx pins\n");
+ return -EINVAL;
+ } else if (count >= 0) {
+ unsigned int pins[IQS7211_NUM_CRX];
+
+ error = fwnode_property_read_u32_array(alp_node,
+ "azoteq,rx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read CRx pins: %d\n",
+ error);
+ return error;
+ }
+
+ reg_field.addr = dev_desc->alp_config;
+ reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0);
+ reg_field.val = 0;
+
+ for (i = 0; i < count; i++) {
+ if (pins[i] < dev_desc->min_crx_alp ||
+ pins[i] >= IQS7211_NUM_CRX) {
+ dev_err(&client->dev, "Invalid CRx pin: %u\n",
+ pins[i]);
+ return -EINVAL;
+ }
+
+ reg_field.val |= BIT(pins[i]);
+ }
+
+ error = iqs7211_add_field(iqs7211, reg_field);
+ if (error)
+ return error;
+ }
+
+ count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable");
+ if (count < 0 && count != -EINVAL) {
+ dev_err(&client->dev, "Failed to count CTx pins: %d\n", count);
+ return count;
+ } else if (count > dev_desc->num_ctx) {
+ dev_err(&client->dev, "Invalid number of CTx pins\n");
+ return -EINVAL;
+ } else if (count >= 0) {
+ unsigned int pins[IQS7211_MAX_CTX];
+
+ error = fwnode_property_read_u32_array(alp_node,
+ "azoteq,tx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read CTx pins: %d\n",
+ error);
+ return error;
+ }
+
+ reg_field.addr = dev_desc->alp_config + 1;
+ reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0);
+ reg_field.val = 0;
+
+ for (i = 0; i < count; i++) {
+ if (pins[i] >= dev_desc->num_ctx) {
+ dev_err(&client->dev, "Invalid CTx pin: %u\n",
+ pins[i]);
+ return -EINVAL;
+ }
+
+ reg_field.val |= BIT(pins[i]);
+ }
+
+ error = iqs7211_add_field(iqs7211, reg_field);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS])
+ (struct iqs7211_private *iqs7211,
+ struct fwnode_handle *reg_grp_node) = {
+ [IQS7211_REG_GRP_TP] = iqs7211_parse_tp,
+ [IQS7211_REG_GRP_ALP] = iqs7211_parse_alp,
+};
+
+static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211,
+ struct fwnode_handle *reg_grp_node,
+ enum iqs7211_reg_grp_id reg_grp)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct iqs7211_reg_field_desc reg_field;
+ int error, i;
+
+ error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp,
+ IQS7211_REG_KEY_NONE);
+ if (error)
+ return error;
+
+ if (iqs7211_parse_extra[reg_grp]) {
+ error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node);
+ if (error)
+ return error;
+ }
+
+ iqs7211->ati_start |= dev_desc->ati_start[reg_grp];
+
+ reg_field.addr = dev_desc->kp_enable[reg_grp];
+ reg_field.mask = 0;
+ reg_field.val = 0;
+
+ for (i = 0; i < dev_desc->num_kp_events; i++) {
+ const char *event_name = dev_desc->kp_events[i].name;
+ struct fwnode_handle *event_node;
+
+ if (dev_desc->kp_events[i].reg_grp != reg_grp)
+ continue;
+
+ reg_field.mask |= dev_desc->kp_events[i].enable;
+
+ if (event_name)
+ event_node = fwnode_get_named_child_node(reg_grp_node,
+ event_name);
+ else
+ event_node = fwnode_handle_get(reg_grp_node);
+
+ if (!event_node)
+ continue;
+
+ error = iqs7211_parse_event(iqs7211, event_node,
+ dev_desc->kp_events[i].reg_grp,
+ dev_desc->kp_events[i].reg_key,
+ &iqs7211->kp_code[i]);
+ fwnode_handle_put(event_node);
+ if (error)
+ return error;
+
+ reg_field.val |= dev_desc->kp_events[i].enable;
+
+ iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp];
+ }
+
+ return iqs7211_add_field(iqs7211, reg_field);
+}
+
+static int iqs7211_register_kp(struct iqs7211_private *iqs7211)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct input_dev *kp_idev = iqs7211->kp_idev;
+ struct i2c_client *client = iqs7211->client;
+ int error, i;
+
+ for (i = 0; i < dev_desc->num_kp_events; i++)
+ if (iqs7211->kp_code[i])
+ break;
+
+ if (i == dev_desc->num_kp_events)
+ return 0;
+
+ kp_idev = devm_input_allocate_device(&client->dev);
+ if (!kp_idev)
+ return -ENOMEM;
+
+ iqs7211->kp_idev = kp_idev;
+
+ kp_idev->name = dev_desc->kp_name;
+ kp_idev->id.bustype = BUS_I2C;
+
+ for (i = 0; i < dev_desc->num_kp_events; i++)
+ if (iqs7211->kp_code[i])
+ input_set_capability(iqs7211->kp_idev, EV_KEY,
+ iqs7211->kp_code[i]);
+
+ error = input_register_device(kp_idev);
+ if (error)
+ dev_err(&client->dev, "Failed to register %s: %d\n",
+ kp_idev->name, error);
+
+ return error;
+}
+
+static int iqs7211_register_tp(struct iqs7211_private *iqs7211)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct touchscreen_properties *prop = &iqs7211->prop;
+ struct input_dev *tp_idev = iqs7211->tp_idev;
+ struct i2c_client *client = iqs7211->client;
+ int error;
+
+ error = device_property_read_u32(&client->dev, "azoteq,num-contacts",
+ &iqs7211->num_contacts);
+ if (error == -EINVAL) {
+ return 0;
+ } else if (error) {
+ dev_err(&client->dev, "Failed to read number of contacts: %d\n",
+ error);
+ return error;
+ } else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) {
+ dev_err(&client->dev, "Invalid number of contacts: %u\n",
+ iqs7211->num_contacts);
+ return -EINVAL;
+ }
+
+ iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1;
+
+ if (!iqs7211->num_contacts)
+ return 0;
+
+ iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE;
+
+ tp_idev = devm_input_allocate_device(&client->dev);
+ if (!tp_idev)
+ return -ENOMEM;
+
+ iqs7211->tp_idev = tp_idev;
+
+ tp_idev->name = dev_desc->tp_name;
+ tp_idev->id.bustype = BUS_I2C;
+
+ input_set_abs_params(tp_idev, ABS_MT_POSITION_X,
+ 0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0);
+
+ input_set_abs_params(tp_idev, ABS_MT_POSITION_Y,
+ 0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0);
+
+ input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0);
+
+ touchscreen_parse_properties(tp_idev, true, prop);
+
+ /*
+ * The device reserves 0xFFFF for coordinates that correspond to slots
+ * which are not in a state of touch.
+ */
+ if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
+ dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
+ prop->max_x, prop->max_y);
+ return -EINVAL;
+ }
+
+ iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x);
+ iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y);
+
+ error = input_mt_init_slots(tp_idev, iqs7211->num_contacts,
+ INPUT_MT_DIRECT);
+ if (error) {
+ dev_err(&client->dev, "Failed to initialize slots: %d\n",
+ error);
+ return error;
+ }
+
+ error = input_register_device(tp_idev);
+ if (error)
+ dev_err(&client->dev, "Failed to register %s: %d\n",
+ tp_idev->name, error);
+
+ return error;
+}
+
+static int iqs7211_report(struct iqs7211_private *iqs7211)
+{
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ struct i2c_client *client = iqs7211->client;
+ struct iqs7211_touch_data *touch_data;
+ u16 info_flags, charge_mode, gesture_flags;
+ __le16 status[12];
+ int error, i;
+
+ error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status,
+ dev_desc->contact_offs * sizeof(__le16) +
+ iqs7211->num_contacts * sizeof(*touch_data));
+ if (error)
+ return error;
+
+ info_flags = le16_to_cpu(status[dev_desc->info_offs]);
+
+ if (info_flags & dev_desc->show_reset) {
+ dev_err(&client->dev, "Unexpected device reset\n");
+
+ /*
+ * The device may or may not expect forced communication after
+ * it exits hardware reset, so the corresponding state machine
+ * must be reset as well.
+ */
+ iqs7211->comms_mode = iqs7211->comms_init;
+
+ return iqs7211_init_device(iqs7211);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) {
+ if (!(info_flags & dev_desc->ati_error[i]))
+ continue;
+
+ dev_err(&client->dev, "Unexpected %s ATI error\n",
+ iqs7211_reg_grp_names[i]);
+ return 0;
+ }
+
+ for (i = 0; i < iqs7211->num_contacts; i++) {
+ u16 pressure;
+
+ touch_data = (struct iqs7211_touch_data *)
+ &status[dev_desc->contact_offs] + i;
+ pressure = le16_to_cpu(touch_data->pressure);
+
+ input_mt_slot(iqs7211->tp_idev, i);
+ if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER,
+ pressure != 0)) {
+ touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop,
+ le16_to_cpu(touch_data->abs_x),
+ le16_to_cpu(touch_data->abs_y),
+ true);
+ input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE,
+ pressure);
+ }
+ }
+
+ if (iqs7211->num_contacts) {
+ input_mt_sync_frame(iqs7211->tp_idev);
+ input_sync(iqs7211->tp_idev);
+ }
+
+ if (!iqs7211->kp_idev)
+ return 0;
+
+ charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2,
+ dev_desc->charge_shift);
+ charge_mode >>= dev_desc->charge_shift;
+
+ /*
+ * A charging mode higher than 2 (idle mode) indicates the device last
+ * operated in low-power mode and intends to express an ALP event.
+ */
+ if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) {
+ input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1);
+ input_sync(iqs7211->kp_idev);
+
+ input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0);
+ }
+
+ for (i = 0; i < dev_desc->num_kp_events; i++) {
+ if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN)
+ continue;
+
+ input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
+ info_flags & dev_desc->kp_events[i].mask);
+ }
+
+ gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]);
+
+ for (i = 0; i < dev_desc->num_kp_events; i++) {
+ enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key;
+ u16 mask = dev_desc->kp_events[i].mask;
+
+ if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP)
+ continue;
+
+ if ((gesture_flags ^ iqs7211->gesture_cache) & mask)
+ input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i],
+ gesture_flags & mask);
+
+ iqs7211->gesture_cache &= ~mask;
+
+ /*
+ * Hold and palm gestures persist while the contact remains in
+ * place; all others are momentary and hence are followed by a
+ * complementary release event.
+ */
+ if (reg_key == IQS7211_REG_KEY_HOLD ||
+ reg_key == IQS7211_REG_KEY_PALM) {
+ iqs7211->gesture_cache |= gesture_flags & mask;
+ gesture_flags &= ~mask;
+ }
+ }
+
+ if (gesture_flags) {
+ input_sync(iqs7211->kp_idev);
+
+ for (i = 0; i < dev_desc->num_kp_events; i++)
+ if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP &&
+ gesture_flags & dev_desc->kp_events[i].mask)
+ input_report_key(iqs7211->kp_idev,
+ iqs7211->kp_code[i], 0);
+ }
+
+ input_sync(iqs7211->kp_idev);
+
+ return 0;
+}
+
+static irqreturn_t iqs7211_irq(int irq, void *context)
+{
+ struct iqs7211_private *iqs7211 = context;
+
+ return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int iqs7211_suspend(struct device *dev)
+{
+ struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ int error;
+
+ if (!dev_desc->suspend || device_may_wakeup(dev))
+ return 0;
+
+ /*
+ * I2C communication prompts the device to assert its RDY pin if it is
+ * not already asserted. As such, the interrupt must be disabled so as
+ * to prevent reentrant interrupts.
+ */
+ disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+ error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl,
+ dev_desc->suspend);
+
+ enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+ return error;
+}
+
+static int iqs7211_resume(struct device *dev)
+{
+ struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+ const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc;
+ __le16 sys_ctrl[] = {
+ 0,
+ cpu_to_le16(iqs7211->event_mask),
+ };
+ int error;
+
+ if (!dev_desc->suspend || device_may_wakeup(dev))
+ return 0;
+
+ disable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+ /*
+ * Forced communication, if in use, must be explicitly enabled as part
+ * of the wake-up command.
+ */
+ error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl,
+ sizeof(sys_ctrl));
+
+ enable_irq(gpiod_to_irq(iqs7211->irq_gpio));
+
+ return error;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume);
+
+static ssize_t fw_info_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iqs7211_private *iqs7211 = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u.%u.%u.%u:%u.%u\n",
+ le16_to_cpu(iqs7211->ver_info.prod_num),
+ le32_to_cpu(iqs7211->ver_info.patch),
+ le16_to_cpu(iqs7211->ver_info.major),
+ le16_to_cpu(iqs7211->ver_info.minor),
+ iqs7211->exp_file[1], iqs7211->exp_file[0]);
+}
+
+static DEVICE_ATTR_RO(fw_info);
+
+static struct attribute *iqs7211_attrs[] = {
+ &dev_attr_fw_info.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(iqs7211);
+
+static const struct of_device_id iqs7211_of_match[] = {
+ {
+ .compatible = "azoteq,iqs7210a",
+ .data = &iqs7211_devs[IQS7210A],
+ },
+ {
+ .compatible = "azoteq,iqs7211a",
+ .data = &iqs7211_devs[IQS7211A],
+ },
+ {
+ .compatible = "azoteq,iqs7211e",
+ .data = &iqs7211_devs[IQS7211E],
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, iqs7211_of_match);
+
+static int iqs7211_probe(struct i2c_client *client)
+{
+ struct iqs7211_private *iqs7211;
+ enum iqs7211_reg_grp_id reg_grp;
+ unsigned long irq_flags;
+ bool shared_irq;
+ int error, irq;
+
+ iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL);
+ if (!iqs7211)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, iqs7211);
+ iqs7211->client = client;
+
+ INIT_LIST_HEAD(&iqs7211->reg_field_head);
+
+ iqs7211->dev_desc = device_get_match_data(&client->dev);
+ if (!iqs7211->dev_desc)
+ return -ENODEV;
+
+ shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX;
+
+ /*
+ * The RDY pin behaves as an interrupt, but must also be polled ahead
+ * of unsolicited I2C communication. As such, it is first opened as a
+ * GPIO and then passed to gpiod_to_irq() to register the interrupt.
+ *
+ * If an extra CTx pin is present, the RDY and MCLR pins are combined
+ * into a single bidirectional pin. In that case, the platform's GPIO
+ * must be configured as an open-drain output.
+ */
+ iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq",
+ shared_irq ? GPIOD_OUT_LOW
+ : GPIOD_IN);
+ if (IS_ERR(iqs7211->irq_gpio)) {
+ error = PTR_ERR(iqs7211->irq_gpio);
+ dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
+ error);
+ return error;
+ }
+
+ if (shared_irq) {
+ iqs7211->reset_gpio = iqs7211->irq_gpio;
+ } else {
+ iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev,
+ "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(iqs7211->reset_gpio)) {
+ error = PTR_ERR(iqs7211->reset_gpio);
+ dev_err(&client->dev,
+ "Failed to request reset GPIO: %d\n", error);
+ return error;
+ }
+ }
+
+ error = iqs7211_start_comms(iqs7211);
+ if (error)
+ return error;
+
+ for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) {
+ const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp];
+ struct fwnode_handle *reg_grp_node;
+
+ if (reg_grp_name)
+ reg_grp_node = device_get_named_child_node(&client->dev,
+ reg_grp_name);
+ else
+ reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
+
+ if (!reg_grp_node)
+ continue;
+
+ error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp);
+ fwnode_handle_put(reg_grp_node);
+ if (error)
+ return error;
+ }
+
+ error = iqs7211_register_kp(iqs7211);
+ if (error)
+ return error;
+
+ error = iqs7211_register_tp(iqs7211);
+ if (error)
+ return error;
+
+ error = iqs7211_init_device(iqs7211);
+ if (error)
+ return error;
+
+ irq = gpiod_to_irq(iqs7211->irq_gpio);
+ if (irq < 0)
+ return irq;
+
+ irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW
+ : IRQF_TRIGGER_HIGH;
+ irq_flags |= IRQF_ONESHOT;
+
+ error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq,
+ irq_flags, client->name, iqs7211);
+ if (error)
+ dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+
+ return error;
+}
+
+static struct i2c_driver iqs7211_i2c_driver = {
+ .probe = iqs7211_probe,
+ .driver = {
+ .name = "iqs7211",
+ .of_match_table = iqs7211_of_match,
+ .dev_groups = iqs7211_groups,
+ .pm = pm_sleep_ptr(&iqs7211_pm),
+ },
+};
+module_i2c_driver(iqs7211_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index 15b5cb763526..9bad8b93c039 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -198,54 +198,36 @@ static void lpc32xx_ts_close(struct input_dev *dev)
static int lpc32xx_ts_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct lpc32xx_tsc *tsc;
struct input_dev *input;
- struct resource *res;
- resource_size_t size;
int irq;
int error;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Can't get memory resource\n");
- return -ENOENT;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- tsc = kzalloc(sizeof(*tsc), GFP_KERNEL);
- input = input_allocate_device();
- if (!tsc || !input) {
- dev_err(&pdev->dev, "failed allocating memory\n");
- error = -ENOMEM;
- goto err_free_mem;
- }
+ tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
+ if (!tsc)
+ return -ENOMEM;
- tsc->dev = input;
tsc->irq = irq;
- size = resource_size(res);
-
- if (!request_mem_region(res->start, size, pdev->name)) {
- dev_err(&pdev->dev, "TSC registers are not free\n");
- error = -EBUSY;
- goto err_free_mem;
- }
+ tsc->tsc_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(tsc->tsc_base))
+ return PTR_ERR(tsc->tsc_base);
- tsc->tsc_base = ioremap(res->start, size);
- if (!tsc->tsc_base) {
- dev_err(&pdev->dev, "Can't map memory\n");
- error = -ENOMEM;
- goto err_release_mem;
- }
-
- tsc->clk = clk_get(&pdev->dev, NULL);
+ tsc->clk = devm_clk_get(dev, NULL);
if (IS_ERR(tsc->clk)) {
dev_err(&pdev->dev, "failed getting clock\n");
- error = PTR_ERR(tsc->clk);
- goto err_unmap;
+ return PTR_ERR(tsc->clk);
+ }
+
+ input = devm_input_allocate_device(dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed allocating input device\n");
+ return -ENOMEM;
}
input->name = MOD_NAME;
@@ -254,68 +236,33 @@ static int lpc32xx_ts_probe(struct platform_device *pdev)
input->id.vendor = 0x0001;
input->id.product = 0x0002;
input->id.version = 0x0100;
- input->dev.parent = &pdev->dev;
input->open = lpc32xx_ts_open;
input->close = lpc32xx_ts_close;
- input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_capability(input, EV_KEY, BTN_TOUCH);
input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL,
LPC32XX_TSC_MAX_XY_VAL, 0, 0);
input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL,
LPC32XX_TSC_MAX_XY_VAL, 0, 0);
input_set_drvdata(input, tsc);
+ tsc->dev = input;
- error = request_irq(tsc->irq, lpc32xx_ts_interrupt,
- 0, pdev->name, tsc);
+ error = devm_request_irq(dev, tsc->irq, lpc32xx_ts_interrupt,
+ 0, pdev->name, tsc);
if (error) {
dev_err(&pdev->dev, "failed requesting interrupt\n");
- goto err_put_clock;
+ return error;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "failed registering input device\n");
- goto err_free_irq;
+ return error;
}
platform_set_drvdata(pdev, tsc);
- device_init_wakeup(&pdev->dev, 1);
-
- return 0;
-
-err_free_irq:
- free_irq(tsc->irq, tsc);
-err_put_clock:
- clk_put(tsc->clk);
-err_unmap:
- iounmap(tsc->tsc_base);
-err_release_mem:
- release_mem_region(res->start, size);
-err_free_mem:
- input_free_device(input);
- kfree(tsc);
-
- return error;
-}
-
-static int lpc32xx_ts_remove(struct platform_device *pdev)
-{
- struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev);
- struct resource *res;
-
- free_irq(tsc->irq, tsc);
-
- input_unregister_device(tsc->dev);
-
- clk_put(tsc->clk);
-
- iounmap(tsc->tsc_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- kfree(tsc);
+ device_init_wakeup(&pdev->dev, true);
return 0;
}
@@ -384,7 +331,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
static struct platform_driver lpc32xx_ts_driver = {
.probe = lpc32xx_ts_probe,
- .remove = lpc32xx_ts_remove,
.driver = {
.name = MOD_NAME,
.pm = LPC32XX_TS_PM_OPS,
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index c39f49720fe4..5abf164ae14c 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -187,16 +187,6 @@ static int wm97xx_acc_startup(struct wm97xx *wm)
"mainstone accelerated touchscreen driver, %d samples/sec\n",
cinfo[sp_idx].speed);
- /* IRQ driven touchscreen is used on Palm hardware */
- if (machine_is_palmt5() || machine_is_palmtx() || machine_is_palmld()) {
- pen_int = 1;
- /* There is some obscure mutant of WM9712 interbred with WM9713
- * used on Palm HW */
- wm->variant = WM97xx_WM1613;
- } else if (machine_is_zylonite()) {
- pen_int = 1;
- }
-
if (pen_int) {
gpiod_irq = gpiod_get(wm->dev, "touch", GPIOD_IN);
if (IS_ERR(gpiod_irq))
@@ -262,13 +252,11 @@ static int mainstone_wm97xx_probe(struct platform_device *pdev)
return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
}
-static int mainstone_wm97xx_remove(struct platform_device *pdev)
+static void mainstone_wm97xx_remove(struct platform_device *pdev)
{
struct wm97xx *wm = platform_get_drvdata(pdev);
wm97xx_unregister_mach_ops(wm);
-
- return 0;
}
static struct platform_driver mainstone_wm97xx_driver = {
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 461023fd6a09..f39633fc8dc2 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -213,7 +213,7 @@ static int max11801_ts_probe(struct i2c_client *client)
}
static const struct i2c_device_id max11801_ts_id[] = {
- {"max11801", 0},
+ { "max11801" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
@@ -230,7 +230,7 @@ static struct i2c_driver max11801_ts_driver = {
.of_match_table = max11801_ts_dt_ids,
},
.id_table = max11801_ts_id,
- .probe_new = max11801_ts_probe,
+ .probe = max11801_ts_probe,
};
module_i2c_driver(max11801_ts_driver);
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index ae0d978c83bf..47b8da00027f 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -42,8 +42,6 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data)
{
struct mc13783_ts_priv *priv = data;
- mc13xxx_irq_ack(priv->mc13xxx, irq);
-
/*
* Kick off reading coordinates. Note that if work happens already
* be queued for future execution (it rearms itself) it will not
@@ -137,8 +135,6 @@ static int mc13783_ts_open(struct input_dev *dev)
mc13xxx_lock(priv->mc13xxx);
- mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS);
-
ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS,
mc13783_ts_handler, MC13783_TS_NAME, priv);
if (ret)
@@ -217,14 +213,12 @@ err_free_mem:
return ret;
}
-static int mc13783_ts_remove(struct platform_device *pdev)
+static void mc13783_ts_remove(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
input_unregister_device(priv->idev);
kfree(priv);
-
- return 0;
}
static struct platform_driver mc13783_ts_driver = {
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
deleted file mode 100644
index ea9517cad695..000000000000
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ /dev/null
@@ -1,287 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
- *
- * Copyright (C) 2009 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * Based on wm97xx-core.c
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/irq.h>
-#include <linux/platform_data/mcs.h>
-#include <linux/slab.h>
-
-/* Registers */
-#define MCS5000_TS_STATUS 0x00
-#define STATUS_OFFSET 0
-#define STATUS_NO (0 << STATUS_OFFSET)
-#define STATUS_INIT (1 << STATUS_OFFSET)
-#define STATUS_SENSING (2 << STATUS_OFFSET)
-#define STATUS_COORD (3 << STATUS_OFFSET)
-#define STATUS_GESTURE (4 << STATUS_OFFSET)
-#define ERROR_OFFSET 4
-#define ERROR_NO (0 << ERROR_OFFSET)
-#define ERROR_POWER_ON_RESET (1 << ERROR_OFFSET)
-#define ERROR_INT_RESET (2 << ERROR_OFFSET)
-#define ERROR_EXT_RESET (3 << ERROR_OFFSET)
-#define ERROR_INVALID_REG_ADDRESS (8 << ERROR_OFFSET)
-#define ERROR_INVALID_REG_VALUE (9 << ERROR_OFFSET)
-
-#define MCS5000_TS_OP_MODE 0x01
-#define RESET_OFFSET 0
-#define RESET_NO (0 << RESET_OFFSET)
-#define RESET_EXT_SOFT (1 << RESET_OFFSET)
-#define OP_MODE_OFFSET 1
-#define OP_MODE_SLEEP (0 << OP_MODE_OFFSET)
-#define OP_MODE_ACTIVE (1 << OP_MODE_OFFSET)
-#define GESTURE_OFFSET 4
-#define GESTURE_DISABLE (0 << GESTURE_OFFSET)
-#define GESTURE_ENABLE (1 << GESTURE_OFFSET)
-#define PROXIMITY_OFFSET 5
-#define PROXIMITY_DISABLE (0 << PROXIMITY_OFFSET)
-#define PROXIMITY_ENABLE (1 << PROXIMITY_OFFSET)
-#define SCAN_MODE_OFFSET 6
-#define SCAN_MODE_INTERRUPT (0 << SCAN_MODE_OFFSET)
-#define SCAN_MODE_POLLING (1 << SCAN_MODE_OFFSET)
-#define REPORT_RATE_OFFSET 7
-#define REPORT_RATE_40 (0 << REPORT_RATE_OFFSET)
-#define REPORT_RATE_80 (1 << REPORT_RATE_OFFSET)
-
-#define MCS5000_TS_SENS_CTL 0x02
-#define MCS5000_TS_FILTER_CTL 0x03
-#define PRI_FILTER_OFFSET 0
-#define SEC_FILTER_OFFSET 4
-
-#define MCS5000_TS_X_SIZE_UPPER 0x08
-#define MCS5000_TS_X_SIZE_LOWER 0x09
-#define MCS5000_TS_Y_SIZE_UPPER 0x0A
-#define MCS5000_TS_Y_SIZE_LOWER 0x0B
-
-#define MCS5000_TS_INPUT_INFO 0x10
-#define INPUT_TYPE_OFFSET 0
-#define INPUT_TYPE_NONTOUCH (0 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_SINGLE (1 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_DUAL (2 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_PALM (3 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_PROXIMITY (7 << INPUT_TYPE_OFFSET)
-#define GESTURE_CODE_OFFSET 3
-#define GESTURE_CODE_NO (0 << GESTURE_CODE_OFFSET)
-
-#define MCS5000_TS_X_POS_UPPER 0x11
-#define MCS5000_TS_X_POS_LOWER 0x12
-#define MCS5000_TS_Y_POS_UPPER 0x13
-#define MCS5000_TS_Y_POS_LOWER 0x14
-#define MCS5000_TS_Z_POS 0x15
-#define MCS5000_TS_WIDTH 0x16
-#define MCS5000_TS_GESTURE_VAL 0x17
-#define MCS5000_TS_MODULE_REV 0x20
-#define MCS5000_TS_FIRMWARE_VER 0x21
-
-/* Touchscreen absolute values */
-#define MCS5000_MAX_XC 0x3ff
-#define MCS5000_MAX_YC 0x3ff
-
-enum mcs5000_ts_read_offset {
- READ_INPUT_INFO,
- READ_X_POS_UPPER,
- READ_X_POS_LOWER,
- READ_Y_POS_UPPER,
- READ_Y_POS_LOWER,
- READ_BLOCK_SIZE,
-};
-
-/* Each client has this additional data */
-struct mcs5000_ts_data {
- struct i2c_client *client;
- struct input_dev *input_dev;
- const struct mcs_platform_data *platform_data;
-};
-
-static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
-{
- struct mcs5000_ts_data *data = dev_id;
- struct i2c_client *client = data->client;
- u8 buffer[READ_BLOCK_SIZE];
- int err;
- int x;
- int y;
-
- err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
- READ_BLOCK_SIZE, buffer);
- if (err < 0) {
- dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
- goto out;
- }
-
- switch (buffer[READ_INPUT_INFO]) {
- case INPUT_TYPE_NONTOUCH:
- input_report_key(data->input_dev, BTN_TOUCH, 0);
- input_sync(data->input_dev);
- break;
-
- case INPUT_TYPE_SINGLE:
- x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
- y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
-
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_report_abs(data->input_dev, ABS_X, x);
- input_report_abs(data->input_dev, ABS_Y, y);
- input_sync(data->input_dev);
- break;
-
- case INPUT_TYPE_DUAL:
- /* TODO */
- break;
-
- case INPUT_TYPE_PALM:
- /* TODO */
- break;
-
- case INPUT_TYPE_PROXIMITY:
- /* TODO */
- break;
-
- default:
- dev_err(&client->dev, "Unknown ts input type %d\n",
- buffer[READ_INPUT_INFO]);
- break;
- }
-
- out:
- return IRQ_HANDLED;
-}
-
-static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
- const struct mcs_platform_data *platform_data)
-{
- struct i2c_client *client = data->client;
-
- /* Touch reset & sleep mode */
- i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
- RESET_EXT_SOFT | OP_MODE_SLEEP);
-
- /* Touch size */
- i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
- platform_data->x_size >> 8);
- i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
- platform_data->x_size & 0xff);
- i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
- platform_data->y_size >> 8);
- i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
- platform_data->y_size & 0xff);
-
- /* Touch active mode & 80 report rate */
- i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
- OP_MODE_ACTIVE | REPORT_RATE_80);
-}
-
-static int mcs5000_ts_probe(struct i2c_client *client)
-{
- const struct mcs_platform_data *pdata;
- struct mcs5000_ts_data *data;
- struct input_dev *input_dev;
- int error;
-
- pdata = dev_get_platdata(&client->dev);
- if (!pdata)
- return -EINVAL;
-
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "Failed to allocate memory\n");
- return -ENOMEM;
- }
-
- data->client = client;
-
- input_dev = devm_input_allocate_device(&client->dev);
- if (!input_dev) {
- dev_err(&client->dev, "Failed to allocate input device\n");
- return -ENOMEM;
- }
-
- input_dev->name = "MELFAS MCS-5000 Touchscreen";
- input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
-
- __set_bit(EV_ABS, input_dev->evbit);
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
-
- data->input_dev = input_dev;
-
- if (pdata->cfg_pin)
- pdata->cfg_pin();
-
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, mcs5000_ts_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "mcs5000_ts", data);
- if (error) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- return error;
- }
-
- error = input_register_device(data->input_dev);
- if (error) {
- dev_err(&client->dev, "Failed to register input device\n");
- return error;
- }
-
- mcs5000_ts_phys_init(data, pdata);
- i2c_set_clientdata(client, data);
-
- return 0;
-}
-
-static int __maybe_unused mcs5000_ts_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
-
- /* Touch sleep mode */
- i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
-
- return 0;
-}
-
-static int __maybe_unused mcs5000_ts_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct mcs5000_ts_data *data = i2c_get_clientdata(client);
- const struct mcs_platform_data *pdata = dev_get_platdata(dev);
-
- mcs5000_ts_phys_init(data, pdata);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(mcs5000_ts_pm, mcs5000_ts_suspend, mcs5000_ts_resume);
-
-static const struct i2c_device_id mcs5000_ts_id[] = {
- { "mcs5000_ts", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
-
-static struct i2c_driver mcs5000_ts_driver = {
- .probe_new = mcs5000_ts_probe,
- .driver = {
- .name = "mcs5000_ts",
- .pm = &mcs5000_ts_pm,
- },
- .id_table = mcs5000_ts_id,
-};
-
-module_i2c_driver(mcs5000_ts_driver);
-
-/* Module information */
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index 4ee8ed4c930c..869884219908 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define MIP4_DEVICE_NAME "mip4_ts"
@@ -466,7 +466,7 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
{
int id;
bool __always_unused hover;
- bool __always_unused palm;
+ bool palm;
bool state;
u16 x, y;
u8 __always_unused pressure_stage = 0;
@@ -522,21 +522,21 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
if (unlikely(id < 0 || id >= MIP4_MAX_FINGERS)) {
dev_err(&ts->client->dev, "Screen - invalid slot ID: %d\n", id);
- } else if (state) {
- /* Press or Move event */
- input_mt_slot(ts->input, id);
- input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true);
+ goto out;
+ }
+
+ input_mt_slot(ts->input, id);
+ if (input_mt_report_slot_state(ts->input,
+ palm ? MT_TOOL_PALM : MT_TOOL_FINGER,
+ state)) {
input_report_abs(ts->input, ABS_MT_POSITION_X, x);
input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
input_report_abs(ts->input, ABS_MT_PRESSURE, pressure);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, touch_major);
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, touch_minor);
- } else {
- /* Release event */
- input_mt_slot(ts->input, id);
- input_mt_report_slot_inactive(ts->input);
}
+out:
input_mt_sync_frame(ts->input);
}
@@ -1336,9 +1336,9 @@ static ssize_t mip4_sysfs_read_fw_version(struct device *dev,
/* Take lock to prevent racing with firmware update */
mutex_lock(&ts->input->mutex);
- count = snprintf(buf, PAGE_SIZE, "%04X %04X %04X %04X\n",
- ts->fw_version.boot, ts->fw_version.core,
- ts->fw_version.app, ts->fw_version.param);
+ count = sysfs_emit(buf, "%04X %04X %04X %04X\n",
+ ts->fw_version.boot, ts->fw_version.core,
+ ts->fw_version.app, ts->fw_version.param);
mutex_unlock(&ts->input->mutex);
@@ -1362,8 +1362,8 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
* product_name shows the name or version of the hardware
* paired with current firmware in the chip.
*/
- count = snprintf(buf, PAGE_SIZE, "%.*s\n",
- (int)sizeof(ts->product_name), ts->product_name);
+ count = sysfs_emit(buf, "%.*s\n",
+ (int)sizeof(ts->product_name), ts->product_name);
mutex_unlock(&ts->input->mutex);
@@ -1382,7 +1382,7 @@ static ssize_t mip4_sysfs_read_product_id(struct device *dev,
mutex_lock(&ts->input->mutex);
- count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
+ count = sysfs_emit(buf, "%04X\n", ts->product_id);
mutex_unlock(&ts->input->mutex);
@@ -1401,8 +1401,8 @@ static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
mutex_lock(&ts->input->mutex);
- count = snprintf(buf, PAGE_SIZE, "%.*s\n",
- (int)sizeof(ts->ic_name), ts->ic_name);
+ count = sysfs_emit(buf, "%.*s\n",
+ (int)sizeof(ts->ic_name), ts->ic_name);
mutex_unlock(&ts->input->mutex);
@@ -1419,10 +1419,7 @@ static struct attribute *mip4_attrs[] = {
&dev_attr_update_fw.attr,
NULL,
};
-
-static const struct attribute_group mip4_attr_group = {
- .attrs = mip4_attrs,
-};
+ATTRIBUTE_GROUPS(mip4);
static int mip4_probe(struct i2c_client *client)
{
@@ -1451,13 +1448,8 @@ static int mip4_probe(struct i2c_client *client)
ts->gpio_ce = devm_gpiod_get_optional(&client->dev,
"ce", GPIOD_OUT_LOW);
- if (IS_ERR(ts->gpio_ce)) {
- error = PTR_ERR(ts->gpio_ce);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->gpio_ce))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->gpio_ce), "Failed to get gpio\n");
error = mip4_power_on(ts);
if (error)
@@ -1483,6 +1475,7 @@ static int mip4_probe(struct i2c_client *client)
input->keycodesize = sizeof(*ts->key_code);
input->keycodemax = ts->key_num;
+ input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0);
input_set_abs_params(input, ABS_MT_PRESSURE,
@@ -1518,17 +1511,10 @@ static int mip4_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &mip4_attr_group);
- if (error) {
- dev_err(&client->dev,
- "Failed to create sysfs attribute group: %d\n", error);
- return error;
- }
-
return 0;
}
-static int __maybe_unused mip4_suspend(struct device *dev)
+static int mip4_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
@@ -1546,7 +1532,7 @@ static int __maybe_unused mip4_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mip4_resume(struct device *dev)
+static int mip4_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
@@ -1564,11 +1550,11 @@ static int __maybe_unused mip4_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
#ifdef CONFIG_OF
static const struct of_device_id mip4_of_match[] = {
- { .compatible = "melfas,"MIP4_DEVICE_NAME, },
+ { .compatible = "melfas,mip4_ts", },
{ },
};
MODULE_DEVICE_TABLE(of, mip4_of_match);
@@ -1583,19 +1569,20 @@ MODULE_DEVICE_TABLE(acpi, mip4_acpi_match);
#endif
static const struct i2c_device_id mip4_i2c_ids[] = {
- { MIP4_DEVICE_NAME, 0 },
- { },
+ { MIP4_DEVICE_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids);
static struct i2c_driver mip4_driver = {
.id_table = mip4_i2c_ids,
- .probe_new = mip4_probe,
+ .probe = mip4_probe,
.driver = {
.name = MIP4_DEVICE_NAME,
+ .dev_groups = mip4_groups,
.of_match_table = of_match_ptr(mip4_of_match),
.acpi_match_table = ACPI_PTR(mip4_acpi_match),
- .pm = &mip4_pm_ops,
+ .pm = pm_sleep_ptr(&mip4_pm_ops),
},
};
module_i2c_driver(mip4_driver);
diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c
index ff0f605f3a3a..7511a134e302 100644
--- a/drivers/input/touchscreen/migor_ts.c
+++ b/drivers/input/touchscreen/migor_ts.c
@@ -186,7 +186,7 @@ static void migor_ts_remove(struct i2c_client *client)
dev_set_drvdata(&client->dev, NULL);
}
-static int __maybe_unused migor_ts_suspend(struct device *dev)
+static int migor_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -197,7 +197,7 @@ static int __maybe_unused migor_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused migor_ts_resume(struct device *dev)
+static int migor_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct migor_ts_priv *priv = i2c_get_clientdata(client);
@@ -208,10 +208,10 @@ static int __maybe_unused migor_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
static const struct i2c_device_id migor_ts_id[] = {
- { "migor_ts", 0 },
+ { "migor_ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, migor_ts_id);
@@ -219,9 +219,9 @@ MODULE_DEVICE_TABLE(i2c, migor_ts_id);
static struct i2c_driver migor_ts_driver = {
.driver = {
.name = "migor_ts",
- .pm = &migor_ts_pm,
+ .pm = pm_sleep_ptr(&migor_ts_pm),
},
- .probe_new = migor_ts_probe,
+ .probe = migor_ts_probe,
.remove = migor_ts_remove,
.id_table = migor_ts_id,
};
diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c
index 758b669391a7..9f947044c4d9 100644
--- a/drivers/input/touchscreen/mms114.c
+++ b/drivers/input/touchscreen/mms114.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
@@ -43,6 +42,7 @@
/* Touchscreen absolute values */
#define MMS114_MAX_AREA 0xff
+#define MMS114_MAX_TOUCHKEYS 15
#define MMS114_MAX_TOUCH 10
#define MMS114_EVENT_SIZE 8
#define MMS136_EVENT_SIZE 6
@@ -70,6 +70,9 @@ struct mms114_data {
unsigned int contact_threshold;
unsigned int moving_threshold;
+ u32 keycodes[MMS114_MAX_TOUCHKEYS];
+ int num_keycodes;
+
/* Use cache data for mode control register(write only) */
u8 cache_mode_control;
};
@@ -167,11 +170,6 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
return;
}
- if (touch->type != MMS114_TYPE_TOUCHSCREEN) {
- dev_err(&client->dev, "Wrong touch type (%d)\n", touch->type);
- return;
- }
-
id = touch->id - 1;
x = touch->x_lo | touch->x_hi << 8;
y = touch->y_lo | touch->y_hi << 8;
@@ -191,9 +189,33 @@ static void mms114_process_mt(struct mms114_data *data, struct mms114_touch *tou
}
}
+static void mms114_process_touchkey(struct mms114_data *data,
+ struct mms114_touch *touch)
+{
+ struct i2c_client *client = data->client;
+ struct input_dev *input_dev = data->input_dev;
+ unsigned int keycode_id;
+
+ if (touch->id == 0)
+ return;
+
+ if (touch->id > data->num_keycodes) {
+ dev_err(&client->dev, "Wrong touch id for touchkey (%d)\n",
+ touch->id);
+ return;
+ }
+
+ keycode_id = touch->id - 1;
+ dev_dbg(&client->dev, "keycode id: %d, pressed: %d\n", keycode_id,
+ touch->pressed);
+
+ input_report_key(input_dev, data->keycodes[keycode_id], touch->pressed);
+}
+
static irqreturn_t mms114_interrupt(int irq, void *dev_id)
{
struct mms114_data *data = dev_id;
+ struct i2c_client *client = data->client;
struct input_dev *input_dev = data->input_dev;
struct mms114_touch touch[MMS114_MAX_TOUCH];
int packet_size;
@@ -223,8 +245,22 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
if (error < 0)
goto out;
- for (index = 0; index < touch_size; index++)
- mms114_process_mt(data, touch + index);
+ for (index = 0; index < touch_size; index++) {
+ switch (touch[index].type) {
+ case MMS114_TYPE_TOUCHSCREEN:
+ mms114_process_mt(data, touch + index);
+ break;
+
+ case MMS114_TYPE_TOUCHKEY:
+ mms114_process_touchkey(data, touch + index);
+ break;
+
+ default:
+ dev_err(&client->dev, "Wrong touch type (%d)\n",
+ touch[index].type);
+ break;
+ }
+ }
input_mt_report_pointer_emulation(data->input_dev, true);
input_sync(data->input_dev);
@@ -446,6 +482,7 @@ static int mms114_probe(struct i2c_client *client)
struct input_dev *input_dev;
const void *match_data;
int error;
+ int i;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "Not supported I2C adapter\n");
@@ -469,6 +506,42 @@ static int mms114_probe(struct i2c_client *client)
data->type = (enum mms_type)match_data;
+ data->num_keycodes = device_property_count_u32(&client->dev,
+ "linux,keycodes");
+ if (data->num_keycodes == -EINVAL) {
+ data->num_keycodes = 0;
+ } else if (data->num_keycodes < 0) {
+ dev_err(&client->dev,
+ "Unable to parse linux,keycodes property: %d\n",
+ data->num_keycodes);
+ return data->num_keycodes;
+ } else if (data->num_keycodes > MMS114_MAX_TOUCHKEYS) {
+ dev_warn(&client->dev,
+ "Found %d linux,keycodes but max is %d, ignoring the rest\n",
+ data->num_keycodes, MMS114_MAX_TOUCHKEYS);
+ data->num_keycodes = MMS114_MAX_TOUCHKEYS;
+ }
+
+ if (data->num_keycodes > 0) {
+ error = device_property_read_u32_array(&client->dev,
+ "linux,keycodes",
+ data->keycodes,
+ data->num_keycodes);
+ if (error) {
+ dev_err(&client->dev,
+ "Unable to read linux,keycodes values: %d\n",
+ error);
+ return error;
+ }
+
+ input_dev->keycode = data->keycodes;
+ input_dev->keycodemax = data->num_keycodes;
+ input_dev->keycodesize = sizeof(data->keycodes[0]);
+ for (i = 0; i < data->num_keycodes; i++)
+ input_set_capability(input_dev,
+ EV_KEY, data->keycodes[i]);
+ }
+
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
@@ -557,7 +630,7 @@ static int mms114_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused mms114_suspend(struct device *dev)
+static int mms114_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
@@ -581,7 +654,7 @@ static int __maybe_unused mms114_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused mms114_resume(struct device *dev)
+static int mms114_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct mms114_data *data = i2c_get_clientdata(client);
@@ -601,10 +674,10 @@ static int __maybe_unused mms114_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
static const struct i2c_device_id mms114_id[] = {
- { "mms114", 0 },
+ { "mms114" },
{ }
};
MODULE_DEVICE_TABLE(i2c, mms114_id);
@@ -635,10 +708,10 @@ MODULE_DEVICE_TABLE(of, mms114_dt_match);
static struct i2c_driver mms114_driver = {
.driver = {
.name = "mms114",
- .pm = &mms114_pm_ops,
+ .pm = pm_sleep_ptr(&mms114_pm_ops),
.of_match_table = of_match_ptr(mms114_dt_match),
},
- .probe_new = mms114_probe,
+ .probe = mms114_probe,
.id_table = mms114_id,
};
diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c
index 4c0816b09d33..a38af3fee34a 100644
--- a/drivers/input/touchscreen/msg2638.c
+++ b/drivers/input/touchscreen/msg2638.c
@@ -441,7 +441,7 @@ static int msg2638_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused msg2638_suspend(struct device *dev)
+static int msg2638_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
@@ -456,7 +456,7 @@ static int __maybe_unused msg2638_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused msg2638_resume(struct device *dev)
+static int msg2638_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
@@ -472,7 +472,7 @@ static int __maybe_unused msg2638_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume);
static const struct msg_chip_data msg2138_data = {
.irq_handler = msg2138_ts_irq_handler,
@@ -492,10 +492,10 @@ static const struct of_device_id msg2638_of_match[] = {
MODULE_DEVICE_TABLE(of, msg2638_of_match);
static struct i2c_driver msg2638_ts_driver = {
- .probe_new = msg2638_ts_probe,
+ .probe = msg2638_ts_probe,
.driver = {
.name = "MStar-TS",
- .pm = &msg2638_pm_ops,
+ .pm = pm_sleep_ptr(&msg2638_pm_ops),
.of_match_table = msg2638_of_match,
},
};
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 28e449eea318..eefae96a2d40 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -128,7 +128,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL);
+ mtouch = kzalloc(sizeof(*mtouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!mtouch || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c
new file mode 100644
index 000000000000..44b58e0dc1ad
--- /dev/null
+++ b/drivers/input/touchscreen/novatek-nvt-ts.c
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Novatek NT11205 i2c touchscreen controller as found
+ * on the Acer Iconia One 7 B1-750 tablet.
+ *
+ * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/module.h>
+
+#include <linux/unaligned.h>
+
+#define NVT_TS_TOUCH_START 0x00
+#define NVT_TS_TOUCH_SIZE 6
+
+#define NVT_TS_PARAMETERS_START 0x78
+/* These are offsets from NVT_TS_PARAMETERS_START */
+#define NVT_TS_PARAMS_WIDTH 0x04
+#define NVT_TS_PARAMS_HEIGHT 0x06
+#define NVT_TS_PARAMS_MAX_TOUCH 0x09
+#define NVT_TS_PARAMS_MAX_BUTTONS 0x0a
+#define NVT_TS_PARAMS_IRQ_TYPE 0x0b
+#define NVT_TS_PARAMS_WAKE_TYPE 0x0c
+#define NVT_TS_PARAMS_CHIP_ID 0x0e
+#define NVT_TS_PARAMS_SIZE 0x0f
+
+#define NVT_TS_MAX_TOUCHES 10
+#define NVT_TS_MAX_SIZE 4096
+
+#define NVT_TS_TOUCH_INVALID 0xff
+#define NVT_TS_TOUCH_SLOT_SHIFT 3
+#define NVT_TS_TOUCH_TYPE_MASK GENMASK(2, 0)
+#define NVT_TS_TOUCH_NEW 1
+#define NVT_TS_TOUCH_UPDATE 2
+#define NVT_TS_TOUCH_RELEASE 3
+
+static const int nvt_ts_irq_type[4] = {
+ IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING,
+ IRQF_TRIGGER_LOW,
+ IRQF_TRIGGER_HIGH
+};
+
+struct nvt_ts_i2c_chip_data {
+ u8 wake_type;
+ u8 chip_id;
+};
+
+struct nvt_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data regulators[2];
+ struct touchscreen_properties prop;
+ int max_touches;
+ u8 buf[NVT_TS_TOUCH_SIZE * NVT_TS_MAX_TOUCHES];
+};
+
+static int nvt_ts_read_data(struct i2c_client *client, u8 reg, u8 *data, int count)
+{
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .len = 1,
+ .buf = &reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = count,
+ .buf = data,
+ }
+ };
+ int ret;
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ dev_err(&client->dev, "Error reading from 0x%02x: %d\n", reg, ret);
+ return (ret < 0) ? ret : -EIO;
+ }
+
+ return 0;
+}
+
+static irqreturn_t nvt_ts_irq(int irq, void *dev_id)
+{
+ struct nvt_ts_data *data = dev_id;
+ struct device *dev = &data->client->dev;
+ int i, error, slot, x, y;
+ bool active;
+ u8 *touch;
+
+ error = nvt_ts_read_data(data->client, NVT_TS_TOUCH_START, data->buf,
+ data->max_touches * NVT_TS_TOUCH_SIZE);
+ if (error)
+ return IRQ_HANDLED;
+
+ for (i = 0; i < data->max_touches; i++) {
+ touch = &data->buf[i * NVT_TS_TOUCH_SIZE];
+
+ if (touch[0] == NVT_TS_TOUCH_INVALID)
+ continue;
+
+ slot = touch[0] >> NVT_TS_TOUCH_SLOT_SHIFT;
+ if (slot < 1 || slot > data->max_touches) {
+ dev_warn(dev, "slot %d out of range, ignoring\n", slot);
+ continue;
+ }
+
+ switch (touch[0] & NVT_TS_TOUCH_TYPE_MASK) {
+ case NVT_TS_TOUCH_NEW:
+ case NVT_TS_TOUCH_UPDATE:
+ active = true;
+ break;
+ case NVT_TS_TOUCH_RELEASE:
+ active = false;
+ break;
+ default:
+ dev_warn(dev, "slot %d unknown state %d\n", slot, touch[0] & 7);
+ continue;
+ }
+
+ slot--;
+ x = (touch[1] << 4) | (touch[3] >> 4);
+ y = (touch[2] << 4) | (touch[3] & 0x0f);
+
+ input_mt_slot(data->input, slot);
+ input_mt_report_slot_state(data->input, MT_TOOL_FINGER, active);
+ touchscreen_report_pos(data->input, &data->prop, x, y, true);
+ }
+
+ input_mt_sync_frame(data->input);
+ input_sync(data->input);
+
+ return IRQ_HANDLED;
+}
+
+static int nvt_ts_start(struct input_dev *dev)
+{
+ struct nvt_ts_data *data = input_get_drvdata(dev);
+ int error;
+
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(&data->client->dev, "failed to enable regulators\n");
+ return error;
+ }
+
+ enable_irq(data->client->irq);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
+
+ return 0;
+}
+
+static void nvt_ts_stop(struct input_dev *dev)
+{
+ struct nvt_ts_data *data = input_get_drvdata(dev);
+
+ disable_irq(data->client->irq);
+ gpiod_set_value_cansleep(data->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
+static int nvt_ts_suspend(struct device *dev)
+{
+ struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ mutex_lock(&data->input->mutex);
+ if (input_device_enabled(data->input))
+ nvt_ts_stop(data->input);
+ mutex_unlock(&data->input->mutex);
+
+ return 0;
+}
+
+static int nvt_ts_resume(struct device *dev)
+{
+ struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ mutex_lock(&data->input->mutex);
+ if (input_device_enabled(data->input))
+ nvt_ts_start(data->input);
+ mutex_unlock(&data->input->mutex);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(nvt_ts_pm_ops, nvt_ts_suspend, nvt_ts_resume);
+
+static int nvt_ts_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ int error, width, height, irq_type;
+ struct nvt_ts_data *data;
+ const struct nvt_ts_i2c_chip_data *chip;
+ struct input_dev *input;
+
+ if (!client->irq) {
+ dev_err(dev, "Error no irq specified\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ chip = device_get_match_data(&client->dev);
+ if (!chip)
+ return -EINVAL;
+
+ data->client = client;
+ i2c_set_clientdata(client, data);
+
+ /*
+ * VCC is the analog voltage supply
+ * IOVCC is the digital voltage supply
+ */
+ data->regulators[0].supply = "vcc";
+ data->regulators[1].supply = "iovcc";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(dev, "cannot get regulators: %d\n", error);
+ return error;
+ }
+
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(dev, "failed to enable regulators: %d\n", error);
+ return error;
+ }
+
+ data->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ error = PTR_ERR_OR_ZERO(data->reset_gpio);
+ if (error) {
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+ dev_err(dev, "failed to request reset GPIO: %d\n", error);
+ return error;
+ }
+
+ /* Wait for controller to come out of reset before params read */
+ msleep(100);
+ error = nvt_ts_read_data(data->client, NVT_TS_PARAMETERS_START,
+ data->buf, NVT_TS_PARAMS_SIZE);
+ gpiod_set_value_cansleep(data->reset_gpio, 1); /* Put back in reset */
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+ if (error)
+ return error;
+
+ width = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_WIDTH]);
+ height = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_HEIGHT]);
+ data->max_touches = data->buf[NVT_TS_PARAMS_MAX_TOUCH];
+ irq_type = data->buf[NVT_TS_PARAMS_IRQ_TYPE];
+
+ if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE ||
+ data->max_touches > NVT_TS_MAX_TOUCHES ||
+ irq_type >= ARRAY_SIZE(nvt_ts_irq_type) ||
+ data->buf[NVT_TS_PARAMS_WAKE_TYPE] != chip->wake_type ||
+ data->buf[NVT_TS_PARAMS_CHIP_ID] != chip->chip_id) {
+ dev_err(dev, "Unsupported touchscreen parameters: %*ph\n",
+ NVT_TS_PARAMS_SIZE, data->buf);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "Detected %dx%d touchscreen with %d max touches\n",
+ width, height, data->max_touches);
+
+ if (data->buf[NVT_TS_PARAMS_MAX_BUTTONS])
+ dev_warn(dev, "Touchscreen buttons are not supported\n");
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = client->name;
+ input->id.bustype = BUS_I2C;
+ input->open = nvt_ts_start;
+ input->close = nvt_ts_stop;
+
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, width - 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, height - 1, 0, 0);
+ touchscreen_parse_properties(input, true, &data->prop);
+
+ error = input_mt_init_slots(input, data->max_touches,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (error)
+ return error;
+
+ data->input = input;
+ input_set_drvdata(input, data);
+
+ error = devm_request_threaded_irq(dev, client->irq, NULL, nvt_ts_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN |
+ nvt_ts_irq_type[irq_type],
+ client->name, data);
+ if (error) {
+ dev_err(dev, "failed to request irq: %d\n", error);
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(dev, "failed to register input device: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct nvt_ts_i2c_chip_data nvt_nt11205_ts_data = {
+ .wake_type = 0x05,
+ .chip_id = 0x05,
+};
+
+static const struct nvt_ts_i2c_chip_data nvt_nt36672a_ts_data = {
+ .wake_type = 0x01,
+ .chip_id = 0x08,
+};
+
+static const struct of_device_id nvt_ts_of_match[] = {
+ { .compatible = "novatek,nt11205-ts", .data = &nvt_nt11205_ts_data },
+ { .compatible = "novatek,nt36672a-ts", .data = &nvt_nt36672a_ts_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nvt_ts_of_match);
+
+static const struct i2c_device_id nvt_ts_i2c_id[] = {
+ { "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data },
+ { "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id);
+
+static struct i2c_driver nvt_ts_driver = {
+ .driver = {
+ .name = "novatek-nvt-ts",
+ .pm = pm_sleep_ptr(&nvt_ts_pm_ops),
+ .of_match_table = nvt_ts_of_match,
+ },
+ .probe = nvt_ts_probe,
+ .id_table = nvt_ts_i2c_id,
+};
+
+module_i2c_driver(nvt_ts_driver);
+
+MODULE_DESCRIPTION("Novatek NT11205 touchscreen driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index b2da0194e02a..083206a3457b 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -197,7 +197,7 @@ fail:
return err;
}
-static int pcap_ts_remove(struct platform_device *pdev)
+static void pcap_ts_remove(struct platform_device *pdev)
{
struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
@@ -207,8 +207,6 @@ static int pcap_ts_remove(struct platform_device *pdev)
input_unregister_device(pcap_ts->input);
kfree(pcap_ts);
-
- return 0;
}
#ifdef CONFIG_PM
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 12abb3b36128..95adede26703 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -199,7 +199,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
int max_x, max_y;
int err;
- pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
+ pm = kzalloc(sizeof(*pm), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pm || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 7959947a3458..dad5786e82a4 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -5,7 +5,7 @@
* Copyright (C) 2010-2011 Pixcir, Inc.
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -13,8 +13,8 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
-#include <linux/of_device.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/slab.h>
#define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */
@@ -44,7 +44,7 @@ enum pixcir_power_mode {
/*
* Interrupt modes:
- * periodical: interrupt is asserted periodicaly
+ * periodical: interrupt is asserted periodically
* diff coordinates: interrupt is asserted when coordinates change
* level on touch: interrupt level asserted during touch
* pulse on touch: interrupt pulse asserted during touch
@@ -405,7 +405,7 @@ static void pixcir_input_close(struct input_dev *dev)
pixcir_stop(ts);
}
-static int __maybe_unused pixcir_i2c_ts_suspend(struct device *dev)
+static int pixcir_i2c_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
@@ -432,7 +432,7 @@ unlock:
return ret;
}
-static int __maybe_unused pixcir_i2c_ts_resume(struct device *dev)
+static int pixcir_i2c_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
@@ -459,8 +459,8 @@ unlock:
return ret;
}
-static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
- pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+ pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
static int pixcir_i2c_ts_probe(struct i2c_client *client)
{
@@ -515,41 +515,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client)
input_set_drvdata(input, tsdata);
tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN);
- if (IS_ERR(tsdata->gpio_attb)) {
- error = PTR_ERR(tsdata->gpio_attb);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to request ATTB gpio: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(tsdata->gpio_attb))
+ return dev_err_probe(dev, PTR_ERR(tsdata->gpio_attb),
+ "Failed to request ATTB gpio\n");
tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_OUT_LOW);
- if (IS_ERR(tsdata->gpio_reset)) {
- error = PTR_ERR(tsdata->gpio_reset);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to request RESET gpio: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(tsdata->gpio_reset))
+ return dev_err_probe(dev, PTR_ERR(tsdata->gpio_reset),
+ "Failed to request RESET gpio\n");
tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake",
GPIOD_OUT_HIGH);
- if (IS_ERR(tsdata->gpio_wake)) {
- error = PTR_ERR(tsdata->gpio_wake);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get wake gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(tsdata->gpio_wake))
+ return dev_err_probe(dev, PTR_ERR(tsdata->gpio_wake),
+ "Failed to get wake gpio\n");
tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
- if (IS_ERR(tsdata->gpio_enable)) {
- error = PTR_ERR(tsdata->gpio_enable);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get enable gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(tsdata->gpio_enable))
+ return dev_err_probe(dev, PTR_ERR(tsdata->gpio_enable),
+ "Failed to get enable gpio\n");
if (tsdata->gpio_enable)
msleep(100);
@@ -614,10 +600,10 @@ MODULE_DEVICE_TABLE(of, pixcir_of_match);
static struct i2c_driver pixcir_i2c_ts_driver = {
.driver = {
.name = "pixcir_ts",
- .pm = &pixcir_dev_pm_ops,
+ .pm = pm_sleep_ptr(&pixcir_dev_pm_ops),
.of_match_table = of_match_ptr(pixcir_of_match),
},
- .probe_new = pixcir_i2c_ts_probe,
+ .probe = pixcir_i2c_ts_probe,
.id_table = pixcir_i2c_ts_id,
};
diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c
index 5000f5fd9ec3..841d39a449b3 100644
--- a/drivers/input/touchscreen/raspberrypi-ts.c
+++ b/drivers/input/touchscreen/raspberrypi-ts.c
@@ -122,20 +122,18 @@ static int rpi_ts_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct input_dev *input;
- struct device_node *fw_node;
struct rpi_firmware *fw;
struct rpi_ts *ts;
u32 touchbuf;
int error;
- fw_node = of_get_parent(np);
+ struct device_node *fw_node __free(device_node) = of_get_parent(np);
if (!fw_node) {
dev_err(dev, "Missing firmware node\n");
return -ENOENT;
}
- fw = rpi_firmware_get(fw_node);
- of_node_put(fw_node);
+ fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
if (!fw)
return -EPROBE_DEFER;
@@ -160,7 +158,6 @@ static int rpi_ts_probe(struct platform_device *pdev)
touchbuf = (u32)ts->fw_regs_phys;
error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF,
&touchbuf, sizeof(touchbuf));
- rpi_firmware_put(fw);
if (error || touchbuf != 0) {
dev_warn(dev, "Failed to set touchbuf, %d\n", error);
return error;
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index d690a17240c2..f975b53e8825 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -24,7 +24,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Slave I2C mode */
#define RM_BOOT_BLDR 0x02
@@ -1004,7 +1004,7 @@ static DEVICE_ATTR(boot_mode, S_IRUGO, raydium_i2c_boot_mode_show, NULL);
static DEVICE_ATTR(update_fw, S_IWUSR, NULL, raydium_i2c_update_fw_store);
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, raydium_i2c_calibrate_store);
-static struct attribute *raydium_i2c_attributes[] = {
+static struct attribute *raydium_i2c_attrs[] = {
&dev_attr_update_fw.attr,
&dev_attr_boot_mode.attr,
&dev_attr_fw_version.attr,
@@ -1012,10 +1012,7 @@ static struct attribute *raydium_i2c_attributes[] = {
&dev_attr_calibrate.attr,
NULL
};
-
-static const struct attribute_group raydium_i2c_attribute_group = {
- .attrs = raydium_i2c_attributes,
-};
+ATTRIBUTE_GROUPS(raydium_i2c);
static int raydium_i2c_power_on(struct raydium_data *ts)
{
@@ -1087,32 +1084,20 @@ static int raydium_i2c_probe(struct i2c_client *client)
i2c_set_clientdata(client, ts);
ts->avdd = devm_regulator_get(&client->dev, "avdd");
- if (IS_ERR(ts->avdd)) {
- error = PTR_ERR(ts->avdd);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get 'avdd' regulator: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->avdd))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->avdd),
+ "Failed to get 'avdd' regulator\n");
ts->vccio = devm_regulator_get(&client->dev, "vccio");
- if (IS_ERR(ts->vccio)) {
- error = PTR_ERR(ts->vccio);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get 'vccio' regulator: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->vccio))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->vccio),
+ "Failed to get 'vccio' regulator\n");
ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_LOW);
- if (IS_ERR(ts->reset_gpio)) {
- error = PTR_ERR(ts->reset_gpio);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "failed to get reset gpio: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->reset_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio),
+ "Failed to get reset gpio\n");
error = raydium_i2c_power_on(ts);
if (error)
@@ -1186,18 +1171,10 @@ static int raydium_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev,
- &raydium_i2c_attribute_group);
- if (error) {
- dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
- error);
- return error;
- }
-
return 0;
}
-static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
+static void raydium_enter_sleep(struct i2c_client *client)
{
static const u8 sleep_cmd[] = { 0x5A, 0xff, 0x00, 0x0f };
int error;
@@ -1209,7 +1186,7 @@ static void __maybe_unused raydium_enter_sleep(struct i2c_client *client)
"sleep command failed: %d\n", error);
}
-static int __maybe_unused raydium_i2c_suspend(struct device *dev)
+static int raydium_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct raydium_data *ts = i2c_get_clientdata(client);
@@ -1229,7 +1206,7 @@ static int __maybe_unused raydium_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused raydium_i2c_resume(struct device *dev)
+static int raydium_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct raydium_data *ts = i2c_get_clientdata(client);
@@ -1246,12 +1223,12 @@ static int __maybe_unused raydium_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
- raydium_i2c_suspend, raydium_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
+ raydium_i2c_suspend, raydium_i2c_resume);
static const struct i2c_device_id raydium_i2c_id[] = {
- { "raydium_i2c", 0 },
- { "rm32380", 0 },
+ { "raydium_i2c" },
+ { "rm32380" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, raydium_i2c_id);
@@ -1273,11 +1250,12 @@ MODULE_DEVICE_TABLE(of, raydium_of_match);
#endif
static struct i2c_driver raydium_i2c_driver = {
- .probe_new = raydium_i2c_probe,
+ .probe = raydium_i2c_probe,
.id_table = raydium_i2c_id,
.driver = {
.name = "raydium_ts",
- .pm = &raydium_i2c_pm_ops,
+ .dev_groups = raydium_i2c_groups,
+ .pm = pm_sleep_ptr(&raydium_i2c_pm_ops),
.acpi_match_table = ACPI_PTR(raydium_acpi_id),
.of_match_table = of_match_ptr(raydium_of_match),
},
diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c
index 6f754a8d30b1..7e761ec73273 100644
--- a/drivers/input/touchscreen/resistive-adc-touch.c
+++ b/drivers/input/touchscreen/resistive-adc-touch.c
@@ -210,12 +210,8 @@ static int grts_probe(struct platform_device *pdev)
/* get the channels from IIO device */
st->iio_chans = devm_iio_channel_get_all(dev);
- if (IS_ERR(st->iio_chans)) {
- error = PTR_ERR(st->iio_chans);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "can't get iio channels.\n");
- return error;
- }
+ if (IS_ERR(st->iio_chans))
+ return dev_err_probe(dev, PTR_ERR(st->iio_chans), "can't get iio channels\n");
if (!device_property_present(dev, "io-channel-names"))
return -ENODEV;
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
index 833422e5fd6d..295d8d75ba32 100644
--- a/drivers/input/touchscreen/rohm_bu21023.c
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -388,13 +388,13 @@ static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
READ_CALIB_BUF(PRM1_Y_L);
- /* X axis ajust */
+ /* X axis adjust */
if (err_x <= 4)
calib_x -= AXIS_ADJUST;
else if (err_x >= 60)
calib_x += AXIS_ADJUST;
- /* Y axis ajust */
+ /* Y axis adjust */
if (err_y <= 4)
calib_y -= AXIS_ADJUST;
else if (err_y >= 60)
@@ -643,12 +643,12 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
const char *firmware_name)
{
struct device *dev = &client->dev;
- const struct firmware *fw;
s32 status;
unsigned int offset, len, xfer_len;
unsigned int retry = 0;
int error, error2;
+ const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, firmware_name, dev);
if (error) {
dev_err(dev, "unable to retrieve firmware %s: %d\n",
@@ -722,18 +722,39 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
- release_firmware(fw);
-
return error ? error : error2;
}
+static int rohm_ts_update_setting(struct rohm_ts_data *ts,
+ unsigned int setting_bit, bool on)
+{
+ int error;
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &ts->input->mutex) {
+ if (on)
+ ts->setup2 |= setting_bit;
+ else
+ ts->setup2 &= ~setting_bit;
+
+ if (ts->initialized) {
+ error = i2c_smbus_write_byte_data(ts->client,
+ COMMON_SETUP2,
+ ts->setup2);
+ if (error)
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
}
static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
@@ -748,22 +769,8 @@ static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= SWAP_XY;
- else
- ts->setup2 &= ~SWAP_XY;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, SWAP_XY, val);
+ return error ?: count;
}
static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
@@ -772,7 +779,7 @@ static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & INV_X));
}
static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
@@ -787,22 +794,8 @@ static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= INV_X;
- else
- ts->setup2 &= ~INV_X;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, INV_X, val);
+ return error ?: count;
}
static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
@@ -811,7 +804,7 @@ static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & INV_Y));
}
static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
@@ -826,22 +819,8 @@ static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= INV_Y;
- else
- ts->setup2 &= ~INV_Y;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, INV_Y, val);
+ return error ?: count;
}
static DEVICE_ATTR_RW(swap_xy);
@@ -854,17 +833,14 @@ static struct attribute *rohm_ts_attrs[] = {
&dev_attr_inv_y.attr,
NULL,
};
-
-static const struct attribute_group rohm_ts_attr_group = {
- .attrs = rohm_ts_attrs,
-};
+ATTRIBUTE_GROUPS(rohm_ts);
static int rohm_ts_device_init(struct i2c_client *client, u8 setup2)
{
struct device *dev = &client->dev;
int error;
- disable_irq(client->irq);
+ guard(disable_irq)(&client->irq);
/*
* Wait 200usec for reset
@@ -1039,10 +1015,10 @@ static int rohm_ts_device_init(struct i2c_client *client, u8 setup2)
/* controller CPU power on */
error = i2c_smbus_write_byte_data(client, SYSTEM,
ANALOG_POWER_ON | CPU_POWER_ON);
+ if (error)
+ return error;
- enable_irq(client->irq);
-
- return error;
+ return 0;
}
static int rohm_ts_power_off(struct i2c_client *client)
@@ -1164,17 +1140,11 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(dev, &rohm_ts_attr_group);
- if (error) {
- dev_err(dev, "failed to create sysfs group: %d\n", error);
- return error;
- }
-
return error;
}
static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
- { BU21023_NAME, 0 },
+ { BU21023_NAME },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
@@ -1182,8 +1152,9 @@ MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
static struct i2c_driver rohm_bu21023_i2c_driver = {
.driver = {
.name = BU21023_NAME,
+ .dev_groups = rohm_ts_groups,
},
- .probe_new = rohm_bu21023_i2c_probe,
+ .probe = rohm_bu21023_i2c_probe,
.id_table = rohm_bu21023_i2c_id,
};
module_i2c_driver(rohm_bu21023_i2c_driver);
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
deleted file mode 100644
index 2e70c0b79444..000000000000
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ /dev/null
@@ -1,464 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Samsung S3C24XX touchscreen driver
- *
- * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
- * Copyright 2008 Ben Dooks <ben-linux@fluff.org>
- * Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
- *
- * Additional work by Herbert Pötzl <herbert@13thfloor.at> and
- * Harald Welte <laforge@openmoko.org>
- */
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <linux/soc/samsung/s3c-adc.h>
-#include <linux/platform_data/touchscreen-s3c2410.h>
-
-#define S3C2410_ADCCON (0x00)
-#define S3C2410_ADCTSC (0x04)
-#define S3C2410_ADCDLY (0x08)
-#define S3C2410_ADCDAT0 (0x0C)
-#define S3C2410_ADCDAT1 (0x10)
-#define S3C64XX_ADCUPDN (0x14)
-#define S3C2443_ADCMUX (0x18)
-#define S3C64XX_ADCCLRINT (0x18)
-#define S5P_ADCMUX (0x1C)
-#define S3C64XX_ADCCLRINTPNDNUP (0x20)
-
-/* ADCTSC Register Bits */
-#define S3C2443_ADCTSC_UD_SEN (1 << 8)
-#define S3C2410_ADCTSC_YM_SEN (1<<7)
-#define S3C2410_ADCTSC_YP_SEN (1<<6)
-#define S3C2410_ADCTSC_XM_SEN (1<<5)
-#define S3C2410_ADCTSC_XP_SEN (1<<4)
-#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3)
-#define S3C2410_ADCTSC_AUTO_PST (1<<2)
-#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0)
-
-/* ADCDAT0 Bits */
-#define S3C2410_ADCDAT0_UPDOWN (1<<15)
-#define S3C2410_ADCDAT0_AUTO_PST (1<<14)
-#define S3C2410_ADCDAT0_XY_PST (0x3<<12)
-#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF)
-
-/* ADCDAT1 Bits */
-#define S3C2410_ADCDAT1_UPDOWN (1<<15)
-#define S3C2410_ADCDAT1_AUTO_PST (1<<14)
-#define S3C2410_ADCDAT1_XY_PST (0x3<<12)
-#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF)
-
-
-#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
-
-#define INT_DOWN (0)
-#define INT_UP (1 << 8)
-
-#define WAIT4INT (S3C2410_ADCTSC_YM_SEN | \
- S3C2410_ADCTSC_YP_SEN | \
- S3C2410_ADCTSC_XP_SEN | \
- S3C2410_ADCTSC_XY_PST(3))
-
-#define AUTOPST (S3C2410_ADCTSC_YM_SEN | \
- S3C2410_ADCTSC_YP_SEN | \
- S3C2410_ADCTSC_XP_SEN | \
- S3C2410_ADCTSC_AUTO_PST | \
- S3C2410_ADCTSC_XY_PST(0))
-
-#define FEAT_PEN_IRQ (1 << 0) /* HAS ADCCLRINTPNDNUP */
-
-/* Per-touchscreen data. */
-
-/**
- * struct s3c2410ts - driver touchscreen state.
- * @client: The ADC client we registered with the core driver.
- * @dev: The device we are bound to.
- * @input: The input device we registered with the input subsystem.
- * @clock: The clock for the adc.
- * @io: Pointer to the IO base.
- * @xp: The accumulated X position data.
- * @yp: The accumulated Y position data.
- * @irq_tc: The interrupt number for pen up/down interrupt
- * @count: The number of samples collected.
- * @shift: The log2 of the maximum count to read in one go.
- * @features: The features supported by the TSADC MOdule.
- */
-struct s3c2410ts {
- struct s3c_adc_client *client;
- struct device *dev;
- struct input_dev *input;
- struct clk *clock;
- void __iomem *io;
- unsigned long xp;
- unsigned long yp;
- int irq_tc;
- int count;
- int shift;
- int features;
-};
-
-static struct s3c2410ts ts;
-
-/**
- * get_down - return the down state of the pen
- * @data0: The data read from ADCDAT0 register.
- * @data1: The data read from ADCDAT1 register.
- *
- * Return non-zero if both readings show that the pen is down.
- */
-static inline bool get_down(unsigned long data0, unsigned long data1)
-{
- /* returns true if both data values show stylus down */
- return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
- !(data1 & S3C2410_ADCDAT0_UPDOWN));
-}
-
-static void touch_timer_fire(struct timer_list *unused)
-{
- unsigned long data0;
- unsigned long data1;
- bool down;
-
- data0 = readl(ts.io + S3C2410_ADCDAT0);
- data1 = readl(ts.io + S3C2410_ADCDAT1);
-
- down = get_down(data0, data1);
-
- if (down) {
- if (ts.count == (1 << ts.shift)) {
- ts.xp >>= ts.shift;
- ts.yp >>= ts.shift;
-
- dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
- __func__, ts.xp, ts.yp, ts.count);
-
- input_report_abs(ts.input, ABS_X, ts.xp);
- input_report_abs(ts.input, ABS_Y, ts.yp);
-
- input_report_key(ts.input, BTN_TOUCH, 1);
- input_sync(ts.input);
-
- ts.xp = 0;
- ts.yp = 0;
- ts.count = 0;
- }
-
- s3c_adc_start(ts.client, 0, 1 << ts.shift);
- } else {
- ts.xp = 0;
- ts.yp = 0;
- ts.count = 0;
-
- input_report_key(ts.input, BTN_TOUCH, 0);
- input_sync(ts.input);
-
- writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
- }
-}
-
-static DEFINE_TIMER(touch_timer, touch_timer_fire);
-
-/**
- * stylus_irq - touchscreen stylus event interrupt
- * @irq: The interrupt number
- * @dev_id: The device ID.
- *
- * Called when the IRQ_TC is fired for a pen up or down event.
- */
-static irqreturn_t stylus_irq(int irq, void *dev_id)
-{
- unsigned long data0;
- unsigned long data1;
- bool down;
-
- data0 = readl(ts.io + S3C2410_ADCDAT0);
- data1 = readl(ts.io + S3C2410_ADCDAT1);
-
- down = get_down(data0, data1);
-
- /* TODO we should never get an interrupt with down set while
- * the timer is running, but maybe we ought to verify that the
- * timer isn't running anyways. */
-
- if (down)
- s3c_adc_start(ts.client, 0, 1 << ts.shift);
- else
- dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
-
- if (ts.features & FEAT_PEN_IRQ) {
- /* Clear pen down/up interrupt */
- writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
- }
-
- return IRQ_HANDLED;
-}
-
-/**
- * s3c24xx_ts_conversion - ADC conversion callback
- * @client: The client that was registered with the ADC core.
- * @data0: The reading from ADCDAT0.
- * @data1: The reading from ADCDAT1.
- * @left: The number of samples left.
- *
- * Called when a conversion has finished.
- */
-static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
- unsigned data0, unsigned data1,
- unsigned *left)
-{
- dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
-
- ts.xp += data0;
- ts.yp += data1;
-
- ts.count++;
-
- /* From tests, it seems that it is unlikely to get a pen-up
- * event during the conversion process which means we can
- * ignore any pen-up events with less than the requisite
- * count done.
- *
- * In several thousand conversions, no pen-ups where detected
- * before count completed.
- */
-}
-
-/**
- * s3c24xx_ts_select - ADC selection callback.
- * @client: The client that was registered with the ADC core.
- * @select: The reason for select.
- *
- * Called when the ADC core selects (or deslects) us as a client.
- */
-static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
-{
- if (select) {
- writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
- ts.io + S3C2410_ADCTSC);
- } else {
- mod_timer(&touch_timer, jiffies+1);
- writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
- }
-}
-
-/**
- * s3c2410ts_probe - device core probe entry point
- * @pdev: The device we are being bound to.
- *
- * Initialise, find and allocate any resources we need to run and then
- * register with the ADC and input systems.
- */
-static int s3c2410ts_probe(struct platform_device *pdev)
-{
- struct s3c2410_ts_mach_info *info;
- struct device *dev = &pdev->dev;
- struct input_dev *input_dev;
- struct resource *res;
- int ret = -EINVAL;
-
- /* Initialise input stuff */
- memset(&ts, 0, sizeof(struct s3c2410ts));
-
- ts.dev = dev;
-
- info = dev_get_platdata(dev);
- if (!info) {
- dev_err(dev, "no platform data, cannot attach\n");
- return -EINVAL;
- }
-
- dev_dbg(dev, "initialising touchscreen\n");
-
- ts.clock = clk_get(dev, "adc");
- if (IS_ERR(ts.clock)) {
- dev_err(dev, "cannot get adc clock source\n");
- return -ENOENT;
- }
-
- ret = clk_prepare_enable(ts.clock);
- if (ret) {
- dev_err(dev, "Failed! to enabled clocks\n");
- goto err_clk_get;
- }
- dev_dbg(dev, "got and enabled clocks\n");
-
- ts.irq_tc = ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "no resource for interrupt\n");
- goto err_clk;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no resource for registers\n");
- ret = -ENOENT;
- goto err_clk;
- }
-
- ts.io = ioremap(res->start, resource_size(res));
- if (ts.io == NULL) {
- dev_err(dev, "cannot map registers\n");
- ret = -ENOMEM;
- goto err_clk;
- }
-
- /* inititalise the gpio */
- if (info->cfg_gpio)
- info->cfg_gpio(to_platform_device(ts.dev));
-
- ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
- s3c24xx_ts_conversion, 1);
- if (IS_ERR(ts.client)) {
- dev_err(dev, "failed to register adc client\n");
- ret = PTR_ERR(ts.client);
- goto err_iomap;
- }
-
- /* Initialise registers */
- if ((info->delay & 0xffff) > 0)
- writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
-
- writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
-
- input_dev = input_allocate_device();
- if (!input_dev) {
- dev_err(dev, "Unable to allocate the input device !!\n");
- ret = -ENOMEM;
- goto err_iomap;
- }
-
- ts.input = input_dev;
- ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
- input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
-
- ts.input->name = "S3C24XX TouchScreen";
- ts.input->id.bustype = BUS_HOST;
- ts.input->id.vendor = 0xDEAD;
- ts.input->id.product = 0xBEEF;
- ts.input->id.version = 0x0102;
-
- ts.shift = info->oversampling_shift;
- ts.features = platform_get_device_id(pdev)->driver_data;
-
- ret = request_irq(ts.irq_tc, stylus_irq, 0,
- "s3c2410_ts_pen", ts.input);
- if (ret) {
- dev_err(dev, "cannot get TC interrupt\n");
- goto err_inputdev;
- }
-
- dev_info(dev, "driver attached, registering input device\n");
-
- /* All went ok, so register to the input system */
- ret = input_register_device(ts.input);
- if (ret < 0) {
- dev_err(dev, "failed to register input device\n");
- ret = -EIO;
- goto err_tcirq;
- }
-
- return 0;
-
- err_tcirq:
- free_irq(ts.irq_tc, ts.input);
- err_inputdev:
- input_free_device(ts.input);
- err_iomap:
- iounmap(ts.io);
- err_clk:
- clk_disable_unprepare(ts.clock);
- del_timer_sync(&touch_timer);
- err_clk_get:
- clk_put(ts.clock);
- return ret;
-}
-
-/**
- * s3c2410ts_remove - device core removal entry point
- * @pdev: The device we are being removed from.
- *
- * Free up our state ready to be removed.
- */
-static int s3c2410ts_remove(struct platform_device *pdev)
-{
- free_irq(ts.irq_tc, ts.input);
- del_timer_sync(&touch_timer);
-
- clk_disable_unprepare(ts.clock);
- clk_put(ts.clock);
-
- input_unregister_device(ts.input);
- iounmap(ts.io);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int s3c2410ts_suspend(struct device *dev)
-{
- writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
- disable_irq(ts.irq_tc);
- clk_disable(ts.clock);
-
- return 0;
-}
-
-static int s3c2410ts_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev);
-
- clk_enable(ts.clock);
- enable_irq(ts.irq_tc);
-
- /* Initialise registers */
- if ((info->delay & 0xffff) > 0)
- writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
-
- writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
-
- return 0;
-}
-
-static const struct dev_pm_ops s3c_ts_pmops = {
- .suspend = s3c2410ts_suspend,
- .resume = s3c2410ts_resume,
-};
-#endif
-
-static const struct platform_device_id s3cts_driver_ids[] = {
- { "s3c2410-ts", 0 },
- { "s3c2440-ts", 0 },
- { "s3c64xx-ts", FEAT_PEN_IRQ },
- { }
-};
-MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
-
-static struct platform_driver s3c_ts_driver = {
- .driver = {
- .name = "samsung-ts",
-#ifdef CONFIG_PM
- .pm = &s3c_ts_pmops,
-#endif
- },
- .id_table = s3cts_driver_ids,
- .probe = s3c2410ts_probe,
- .remove = s3c2410ts_remove,
-};
-module_platform_driver(s3c_ts_driver);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
- "Ben Dooks <ben@simtec.co.uk>, "
- "Simtec Electronics <linux@simtec.co.uk>");
-MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c
index cc417c03aaca..e1518a75a51b 100644
--- a/drivers/input/touchscreen/s6sy761.c
+++ b/drivers/input/touchscreen/s6sy761.c
@@ -4,7 +4,7 @@
// Copyright (c) 2017 Samsung Electronics Co., Ltd.
// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
@@ -286,10 +286,7 @@ static struct attribute *s6sy761_sysfs_attrs[] = {
&dev_attr_devid.attr,
NULL
};
-
-static struct attribute_group s6sy761_attribute_group = {
- .attrs = s6sy761_sysfs_attrs
-};
+ATTRIBUTE_GROUPS(s6sy761_sysfs);
static int s6sy761_power_on(struct s6sy761_data *sdata)
{
@@ -465,10 +462,6 @@ static int s6sy761_probe(struct i2c_client *client)
if (err)
return err;
- err = devm_device_add_group(&client->dev, &s6sy761_attribute_group);
- if (err)
- return err;
-
pm_runtime_enable(&client->dev);
return 0;
@@ -479,7 +472,7 @@ static void s6sy761_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
}
-static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
+static int s6sy761_runtime_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -487,7 +480,7 @@ static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP);
}
-static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
+static int s6sy761_runtime_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -495,7 +488,7 @@ static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL);
}
-static int __maybe_unused s6sy761_suspend(struct device *dev)
+static int s6sy761_suspend(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -504,7 +497,7 @@ static int __maybe_unused s6sy761_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused s6sy761_resume(struct device *dev)
+static int s6sy761_resume(struct device *dev)
{
struct s6sy761_data *sdata = dev_get_drvdata(dev);
@@ -514,9 +507,8 @@ static int __maybe_unused s6sy761_resume(struct device *dev)
}
static const struct dev_pm_ops s6sy761_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
- SET_RUNTIME_PM_OPS(s6sy761_runtime_suspend,
- s6sy761_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
+ RUNTIME_PM_OPS(s6sy761_runtime_suspend, s6sy761_runtime_resume, NULL)
};
#ifdef CONFIG_OF
@@ -528,18 +520,19 @@ MODULE_DEVICE_TABLE(of, s6sy761_of_match);
#endif
static const struct i2c_device_id s6sy761_id[] = {
- { "s6sy761", 0 },
- { },
+ { "s6sy761" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, s6sy761_id);
static struct i2c_driver s6sy761_driver = {
.driver = {
.name = S6SY761_DEV_NAME,
+ .dev_groups = s6sy761_sysfs_groups,
.of_match_table = of_match_ptr(s6sy761_of_match),
- .pm = &s6sy761_pm_ops,
+ .pm = pm_ptr(&s6sy761_pm_ops),
},
- .probe_new = s6sy761_probe,
+ .probe = s6sy761_probe,
.remove = s6sy761_remove,
.id_table = s6sy761_id,
};
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 8a7351c4414c..5ccc96764742 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -24,7 +24,7 @@
#include <linux/irq.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SILEAD_TS_NAME "silead_ts"
@@ -71,7 +71,6 @@ struct silead_ts_data {
struct regulator_bulk_data regulators[2];
char fw_name[64];
struct touchscreen_properties prop;
- u32 max_fingers;
u32 chip_id;
struct input_mt_pos pos[SILEAD_MAX_FINGERS];
int slots[SILEAD_MAX_FINGERS];
@@ -136,7 +135,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data)
touchscreen_parse_properties(data->input, true, &data->prop);
silead_apply_efi_fw_min_max(data);
- input_mt_init_slots(data->input, data->max_fingers,
+ input_mt_init_slots(data->input, SILEAD_MAX_FINGERS,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED |
INPUT_MT_TRACK);
@@ -256,10 +255,10 @@ static void silead_ts_read_data(struct i2c_client *client)
return;
}
- if (buf[0] > data->max_fingers) {
+ if (buf[0] > SILEAD_MAX_FINGERS) {
dev_warn(dev, "More touches reported then supported %d > %d\n",
- buf[0], data->max_fingers);
- buf[0] = data->max_fingers;
+ buf[0], SILEAD_MAX_FINGERS);
+ buf[0] = SILEAD_MAX_FINGERS;
}
if (silead_ts_handle_pen_data(data, buf))
@@ -315,7 +314,6 @@ sync:
static int silead_ts_init(struct i2c_client *client)
{
- struct silead_ts_data *data = i2c_get_clientdata(client);
int error;
error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET,
@@ -325,7 +323,7 @@ static int silead_ts_init(struct i2c_client *client)
usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR,
- data->max_fingers);
+ SILEAD_MAX_FINGERS);
if (error)
goto i2c_write_err;
usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX);
@@ -591,13 +589,6 @@ static void silead_ts_read_props(struct i2c_client *client)
const char *str;
int error;
- error = device_property_read_u32(dev, "silead,max-fingers",
- &data->max_fingers);
- if (error) {
- dev_dbg(dev, "Max fingers read error %d\n", error);
- data->max_fingers = 5; /* Most devices handle up-to 5 fingers */
- }
-
error = device_property_read_string(dev, "firmware-name", &str);
if (!error)
snprintf(data->fw_name, sizeof(data->fw_name),
@@ -706,11 +697,9 @@ static int silead_ts_probe(struct i2c_client *client)
/* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
- if (IS_ERR(data->gpio_power)) {
- if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
- dev_err(dev, "Shutdown GPIO request failed\n");
- return PTR_ERR(data->gpio_power);
- }
+ if (IS_ERR(data->gpio_power))
+ return dev_err_probe(dev, PTR_ERR(data->gpio_power),
+ "Shutdown GPIO request failed\n");
error = silead_ts_setup(client);
if (error)
@@ -736,7 +725,7 @@ static int silead_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused silead_ts_suspend(struct device *dev)
+static int silead_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -745,7 +734,7 @@ static int __maybe_unused silead_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused silead_ts_resume(struct device *dev)
+static int silead_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
bool second_try = false;
@@ -784,15 +773,15 @@ static int __maybe_unused silead_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
static const struct i2c_device_id silead_ts_id[] = {
- { "gsl1680", 0 },
- { "gsl1688", 0 },
- { "gsl3670", 0 },
- { "gsl3675", 0 },
- { "gsl3692", 0 },
- { "mssl1680", 0 },
+ { "gsl1680" },
+ { "gsl1688" },
+ { "gsl3670" },
+ { "gsl3675" },
+ { "gsl3692" },
+ { "mssl1680" },
{ }
};
MODULE_DEVICE_TABLE(i2c, silead_ts_id);
@@ -826,13 +815,13 @@ MODULE_DEVICE_TABLE(of, silead_ts_of_match);
#endif
static struct i2c_driver silead_ts_driver = {
- .probe_new = silead_ts_probe,
+ .probe = silead_ts_probe,
.id_table = silead_ts_id,
.driver = {
.name = SILEAD_TS_NAME,
.acpi_match_table = ACPI_PTR(silead_ts_acpi_match),
.of_match_table = of_match_ptr(silead_ts_of_match),
- .pm = &silead_ts_pm,
+ .pm = pm_sleep_ptr(&silead_ts_pm),
},
};
module_i2c_driver(silead_ts_driver);
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c
index 5a493b15b25d..a625f2ad809d 100644
--- a/drivers/input/touchscreen/sis_i2c.c
+++ b/drivers/input/touchscreen/sis_i2c.c
@@ -15,7 +15,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SIS_I2C_NAME "sis_i2c_ts"
@@ -310,23 +310,15 @@ static int sis_ts_probe(struct i2c_client *client)
ts->attn_gpio = devm_gpiod_get_optional(&client->dev,
"attn", GPIOD_IN);
- if (IS_ERR(ts->attn_gpio)) {
- error = PTR_ERR(ts->attn_gpio);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get attention GPIO: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->attn_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->attn_gpio),
+ "Failed to get attention GPIO\n");
ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
"reset", GPIOD_OUT_LOW);
- if (IS_ERR(ts->reset_gpio)) {
- error = PTR_ERR(ts->reset_gpio);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev,
- "Failed to get reset GPIO: %d\n", error);
- return error;
- }
+ if (IS_ERR(ts->reset_gpio))
+ return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio),
+ "Failed to get reset GPIO\n");
sis_ts_reset(ts);
@@ -382,8 +374,8 @@ MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
#endif
static const struct i2c_device_id sis_ts_id[] = {
- { SIS_I2C_NAME, 0 },
- { "9200-ts", 0 },
+ { SIS_I2C_NAME },
+ { "9200-ts" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, sis_ts_id);
@@ -393,7 +385,7 @@ static struct i2c_driver sis_ts_driver = {
.name = SIS_I2C_NAME,
.of_match_table = of_match_ptr(sis_ts_dt_ids),
},
- .probe_new = sis_ts_probe,
+ .probe = sis_ts_probe,
.id_table = sis_ts_id,
};
module_i2c_driver(sis_ts_driver);
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index bd68633dc6c0..9b3901eec0a5 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -22,6 +22,7 @@
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/input/touch-overlay.h>
#define ST1232_TS_NAME "st1232-ts"
#define ST1633_TS_NAME "st1633-ts"
@@ -57,6 +58,7 @@ struct st1232_ts_data {
struct dev_pm_qos_request low_latency_req;
struct gpio_desc *reset_gpio;
const struct st_chip_info *chip_info;
+ struct list_head touch_overlay_list;
int read_buf_len;
u8 *read_buf;
};
@@ -156,6 +158,10 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_mt_assign_slots(input, slots, pos, n_contacts, 0);
for (i = 0; i < n_contacts; i++) {
+ if (touch_overlay_process_contact(&ts->touch_overlay_list,
+ input, &pos[i], slots[i]))
+ continue;
+
input_mt_slot(input, slots[i]);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
@@ -164,6 +170,7 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]);
}
+ touch_overlay_sync_frame(&ts->touch_overlay_list, input);
input_mt_sync_frame(input);
input_sync(input);
@@ -292,18 +299,30 @@ static int st1232_ts_probe(struct i2c_client *client)
if (error)
return error;
- /* Read resolution from the chip */
- error = st1232_ts_read_resolution(ts, &max_x, &max_y);
- if (error) {
- dev_err(&client->dev,
- "Failed to read resolution: %d\n", error);
- return error;
- }
-
if (ts->chip_info->have_z)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->chip_info->max_area, 0, 0);
+ /* map overlay objects if defined in the device tree */
+ INIT_LIST_HEAD(&ts->touch_overlay_list);
+ error = touch_overlay_map(&ts->touch_overlay_list, input_dev);
+ if (error)
+ return error;
+
+ if (touch_overlay_mapped_touchscreen(&ts->touch_overlay_list)) {
+ /* Read resolution from the overlay touchscreen if defined */
+ touch_overlay_get_touchscreen_abs(&ts->touch_overlay_list,
+ &max_x, &max_y);
+ } else {
+ /* Read resolution from the chip */
+ error = st1232_ts_read_resolution(ts, &max_x, &max_y);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read resolution: %d\n", error);
+ return error;
+ }
+ }
+
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
@@ -340,7 +359,7 @@ static int st1232_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused st1232_ts_suspend(struct device *dev)
+static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *ts = i2c_get_clientdata(client);
@@ -353,7 +372,7 @@ static int __maybe_unused st1232_ts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused st1232_ts_resume(struct device *dev)
+static int st1232_ts_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *ts = i2c_get_clientdata(client);
@@ -366,8 +385,8 @@ static int __maybe_unused st1232_ts_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
- st1232_ts_suspend, st1232_ts_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
+ st1232_ts_suspend, st1232_ts_resume);
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, (unsigned long)&st1232_chip_info },
@@ -384,13 +403,13 @@ static const struct of_device_id st1232_ts_dt_ids[] = {
MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
static struct i2c_driver st1232_ts_driver = {
- .probe_new = st1232_ts_probe,
+ .probe = st1232_ts_probe,
.id_table = st1232_ts_id,
.driver = {
.name = ST1232_TS_NAME,
.of_match_table = st1232_ts_dt_ids,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .pm = &st1232_ts_pm_ops,
+ .pm = pm_sleep_ptr(&st1232_ts_pm_ops),
},
};
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index d092e89d40e8..119cd26851cf 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -517,10 +517,7 @@ static struct attribute *stmfts_sysfs_attrs[] = {
&dev_attr_hover_enable.attr,
NULL
};
-
-static struct attribute_group stmfts_attribute_group = {
- .attrs = stmfts_sysfs_attrs
-};
+ATTRIBUTE_GROUPS(stmfts_sysfs);
static int stmfts_power_on(struct stmfts_data *sdata)
{
@@ -727,10 +724,6 @@ static int stmfts_probe(struct i2c_client *client)
}
}
- err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
- if (err)
- return err;
-
pm_runtime_enable(&client->dev);
device_enable_async_suspend(&client->dev);
@@ -742,7 +735,7 @@ static void stmfts_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
}
-static int __maybe_unused stmfts_runtime_suspend(struct device *dev)
+static int stmfts_runtime_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
@@ -754,7 +747,7 @@ static int __maybe_unused stmfts_runtime_suspend(struct device *dev)
return ret;
}
-static int __maybe_unused stmfts_runtime_resume(struct device *dev)
+static int stmfts_runtime_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
@@ -766,7 +759,7 @@ static int __maybe_unused stmfts_runtime_resume(struct device *dev)
return ret;
}
-static int __maybe_unused stmfts_suspend(struct device *dev)
+static int stmfts_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
@@ -775,7 +768,7 @@ static int __maybe_unused stmfts_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused stmfts_resume(struct device *dev)
+static int stmfts_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
@@ -783,8 +776,8 @@ static int __maybe_unused stmfts_resume(struct device *dev)
}
static const struct dev_pm_ops stmfts_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
- SET_RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
+ RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
};
#ifdef CONFIG_OF
@@ -796,19 +789,20 @@ MODULE_DEVICE_TABLE(of, stmfts_of_match);
#endif
static const struct i2c_device_id stmfts_id[] = {
- { "stmfts", 0 },
- { },
+ { "stmfts" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, stmfts_id);
static struct i2c_driver stmfts_driver = {
.driver = {
.name = STMFTS_DEV_NAME,
+ .dev_groups = stmfts_sysfs_groups,
.of_match_table = of_match_ptr(stmfts_of_match),
- .pm = &stmfts_pm_ops,
+ .pm = pm_ptr(&stmfts_pm_ops),
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
- .probe_new = stmfts_probe,
+ .probe = stmfts_probe,
.remove = stmfts_remove,
.id_table = stmfts_id,
};
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index 25c45c3a3561..af0fb38bcfdc 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -107,7 +107,7 @@ static void stmpe_work(struct work_struct *work)
/*
* touch_det sometimes get desasserted or just get stuck. This appears
- * to be a silicon bug, We still have to clearify this with the
+ * to be a silicon bug, We still have to clarify this with the
* manufacture. As a workaround We release the key anyway if the
* touch_det keeps coming in after 4ms, while the FIFO contains no value
* during the whole time.
@@ -140,7 +140,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
/*
* The FIFO sometimes just crashes and stops generating interrupts. This
- * appears to be a silicon bug. We still have to clearify this with
+ * appears to be a silicon bug. We still have to clarify this with
* the manufacture. As a workaround we disable the TSC while we are
* collecting data and flush the FIFO after reading
*/
@@ -350,13 +350,11 @@ static int stmpe_input_probe(struct platform_device *pdev)
return 0;
}
-static int stmpe_ts_remove(struct platform_device *pdev)
+static void stmpe_ts_remove(struct platform_device *pdev)
{
struct stmpe_touch *ts = platform_get_drvdata(pdev);
stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN);
-
- return 0;
}
static struct platform_driver stmpe_ts_driver = {
@@ -368,12 +366,7 @@ static struct platform_driver stmpe_ts_driver = {
};
module_platform_driver(stmpe_ts_driver);
-static const struct of_device_id stmpe_ts_ids[] = {
- { .compatible = "st,stmpe-ts", },
- { },
-};
-MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
-
+MODULE_ALIAS("platform:stmpe-ts");
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 73eb8f80be6e..e8286060043a 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -22,7 +22,7 @@
* in the kernel). So this driver offers straight forward, reliable single
* touch functionality only.
*
- * s.a. A20 User Manual "1.15 TP" (Documentation/arm/sunxi.rst)
+ * s.a. A20 User Manual "1.15 TP" (Documentation/arch/arm/sunxi.rst)
* (looks like the description in the A20 User Manual v1.3 is better
* than the one in the A10 User Manual v.1.5)
*/
@@ -194,7 +194,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, int *temp)
static int sun4i_get_tz_temp(struct thermal_zone_device *tz, int *temp)
{
- return sun4i_get_temp(tz->devdata, temp);
+ return sun4i_get_temp(thermal_zone_device_priv(tz), temp);
}
static const struct thermal_zone_device_ops sun4i_ts_tz_ops = {
@@ -375,7 +375,7 @@ static int sun4i_ts_probe(struct platform_device *pdev)
return 0;
}
-static int sun4i_ts_remove(struct platform_device *pdev)
+static void sun4i_ts_remove(struct platform_device *pdev)
{
struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
@@ -385,8 +385,6 @@ static int sun4i_ts_remove(struct platform_device *pdev)
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
-
- return 0;
}
static const struct of_device_id sun4i_ts_of_match[] = {
@@ -398,9 +396,9 @@ static const struct of_device_id sun4i_ts_of_match[] = {
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
static struct platform_driver sun4i_ts_driver = {
- .driver = {
+ .driver = {
.name = "sun4i-ts",
- .of_match_table = of_match_ptr(sun4i_ts_of_match),
+ .of_match_table = sun4i_ts_of_match,
},
.probe = sun4i_ts_probe,
.remove = sun4i_ts_remove,
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 8ddb3f7d307a..7b3b10cbfcfc 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -421,7 +421,7 @@ static void sur40_report_blob(struct sur40_blob *blob, struct input_dev *input)
if (blob->type != SUR40_TOUCH)
return;
- slotnum = input_mt_get_slot_by_key(input, blob->blob_id);
+ slotnum = input_mt_get_slot_by_key(input, le16_to_cpu(blob->blob_id));
if (slotnum < 0 || slotnum >= MAX_CONTACTS)
return;
@@ -672,7 +672,7 @@ static int sur40_probe(struct usb_interface *interface,
return -ENODEV;
/* Allocate memory for our device state and initialize it. */
- sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL);
+ sur40 = kzalloc(sizeof(*sur40), GFP_KERNEL);
if (!sur40)
return -ENOMEM;
@@ -847,9 +847,10 @@ static int sur40_queue_setup(struct vb2_queue *q,
unsigned int sizes[], struct device *alloc_devs[])
{
struct sur40_state *sur40 = vb2_get_drv_priv(q);
+ unsigned int q_num_bufs = vb2_get_num_buffers(q);
- if (q->num_buffers + *nbuffers < 3)
- *nbuffers = 3 - q->num_buffers;
+ if (q_num_bufs + *nbuffers < 3)
+ *nbuffers = 3 - q_num_bufs;
if (*nplanes)
return sizes[0] < sur40->pix_fmt.sizeimage ? -EINVAL : 0;
@@ -1107,8 +1108,6 @@ static const struct vb2_ops sur40_queue_ops = {
.buf_queue = sur40_buffer_queue,
.start_streaming = sur40_start_streaming,
.stop_streaming = sur40_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue sur40_queue = {
@@ -1123,7 +1122,7 @@ static const struct vb2_queue sur40_queue = {
.ops = &sur40_queue_ops,
.mem_ops = &vb2_dma_sg_memops,
.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC,
- .min_buffers_needed = 3,
+ .min_queued_buffers = 3,
};
static const struct v4l2_file_operations sur40_video_fops = {
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index 1da23e5585a0..6074b7730e86 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -18,7 +18,7 @@
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SURFACE3_PACKET_SIZE 264
@@ -221,7 +221,6 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on)
*/
static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
{
- int error;
struct device *dev;
struct gpio_desc *gpiod;
int i;
@@ -231,15 +230,9 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
/* Get the reset lines GPIO pin number */
for (i = 0; i < 2; i++) {
gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
- if (IS_ERR(gpiod)) {
- error = PTR_ERR(gpiod);
- if (error != -EPROBE_DEFER)
- dev_err(dev,
- "Failed to get power GPIO %d: %d\n",
- i,
- error);
- return error;
- }
+ if (IS_ERR(gpiod))
+ return dev_err_probe(dev, PTR_ERR(gpiod),
+ "Failed to get power GPIO %d\n", i);
data->gpiod_rst[i] = gpiod;
}
@@ -369,7 +362,7 @@ static int surface3_spi_probe(struct spi_device *spi)
return 0;
}
-static int __maybe_unused surface3_spi_suspend(struct device *dev)
+static int surface3_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct surface3_ts_data *data = spi_get_drvdata(spi);
@@ -381,7 +374,7 @@ static int __maybe_unused surface3_spi_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused surface3_spi_resume(struct device *dev)
+static int surface3_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct surface3_ts_data *data = spi_get_drvdata(spi);
@@ -393,9 +386,9 @@ static int __maybe_unused surface3_spi_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
- surface3_spi_suspend,
- surface3_spi_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
+ surface3_spi_suspend,
+ surface3_spi_resume);
#ifdef CONFIG_ACPI
static const struct acpi_device_id surface3_spi_acpi_match[] = {
@@ -409,7 +402,7 @@ static struct spi_driver surface3_spi_driver = {
.driver = {
.name = "Surface3-spi",
.acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
- .pm = &surface3_spi_pm_ops,
+ .pm = pm_sleep_ptr(&surface3_spi_pm_ops),
},
.probe = surface3_spi_probe,
};
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index 52ae73035830..5fa47a1a6fdc 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -116,7 +116,7 @@ static inline void sx865x_penrelease(struct sx8654 *ts)
static void sx865x_penrelease_timer_handler(struct timer_list *t)
{
- struct sx8654 *ts = from_timer(ts, t, timer);
+ struct sx8654 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -290,7 +290,7 @@ static void sx8654_close(struct input_dev *dev)
disable_irq(client->irq);
if (!sx8654->data->has_irq_penrelease)
- del_timer_sync(&sx8654->timer);
+ timer_delete_sync(&sx8654->timer);
/* enable manual mode mode */
error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
@@ -323,13 +323,9 @@ static int sx8654_probe(struct i2c_client *client)
sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(sx8654->gpio_reset)) {
- error = PTR_ERR(sx8654->gpio_reset);
- if (error != -EPROBE_DEFER)
- dev_err(&client->dev, "unable to get reset-gpio: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(sx8654->gpio_reset))
+ return dev_err_probe(&client->dev, PTR_ERR(sx8654->gpio_reset),
+ "unable to get reset-gpio\n");
dev_dbg(&client->dev, "got GPIO reset pin\n");
sx8654->data = device_get_match_data(&client->dev);
@@ -470,7 +466,7 @@ static struct i2c_driver sx8654_driver = {
.of_match_table = of_match_ptr(sx8654_of_match),
},
.id_table = sx8654_id_table,
- .probe_new = sx8654_probe,
+ .probe = sx8654_probe,
};
module_i2c_driver(sx8654_driver);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index f2fb6a9a1a57..93d659ff90aa 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -25,7 +25,6 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/sort.h>
#include <linux/pm_wakeirq.h>
@@ -158,7 +157,6 @@ static void titsc_step_config(struct titsc *ts_dev)
n++ == 0 ? STEPCONFIG_OPENDLY : 0);
}
- config = 0;
config = STEPCONFIG_MODE_HWSYNC |
STEPCONFIG_AVG_16 | ts_dev->bit_yn |
STEPCONFIG_INM_ADCREFM;
@@ -492,7 +490,7 @@ err_free_mem:
return err;
}
-static int titsc_remove(struct platform_device *pdev)
+static void titsc_remove(struct platform_device *pdev)
{
struct titsc *ts_dev = platform_get_drvdata(pdev);
u32 steps;
@@ -509,10 +507,9 @@ static int titsc_remove(struct platform_device *pdev)
input_unregister_device(ts_dev->input);
kfree(ts_dev);
- return 0;
}
-static int __maybe_unused titsc_suspend(struct device *dev)
+static int titsc_suspend(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
unsigned int idle;
@@ -527,7 +524,7 @@ static int __maybe_unused titsc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused titsc_resume(struct device *dev)
+static int titsc_resume(struct device *dev)
{
struct titsc *ts_dev = dev_get_drvdata(dev);
@@ -543,7 +540,7 @@ static int __maybe_unused titsc_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(titsc_pm_ops, titsc_suspend, titsc_resume);
static const struct of_device_id ti_tsc_dt_ids[] = {
{ .compatible = "ti,am3359-tsc", },
@@ -555,8 +552,8 @@ static struct platform_driver ti_tsc_driver = {
.probe = titsc_probe,
.remove = titsc_remove,
.driver = {
- .name = "TI-am335x-tsc",
- .pm = &titsc_pm_ops,
+ .name = "TI-am335x-tsc",
+ .pm = pm_sleep_ptr(&titsc_pm_ops),
.of_match_table = ti_tsc_dt_ids,
},
};
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index fb49687da405..c2718350815c 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -139,7 +139,7 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- touchit213 = kzalloc(sizeof(struct touchit213), GFP_KERNEL);
+ touchit213 = kzalloc(sizeof(*touchit213), GFP_KERNEL);
input_dev = input_allocate_device();
if (!touchit213 || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 3cd58a13e44f..30ba97bd00a1 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -102,7 +102,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tr = kzalloc(sizeof(struct tr), GFP_KERNEL);
+ tr = kzalloc(sizeof(*tr), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tr || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index bde3c6ee3c60..fbd72789ea80 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -109,7 +109,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
+ tw = kzalloc(sizeof(*tw), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tw || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c
index 6cf66aadc10e..98422d1e80d6 100644
--- a/drivers/input/touchscreen/ts4800-ts.c
+++ b/drivers/input/touchscreen/ts4800-ts.c
@@ -110,18 +110,17 @@ static int ts4800_parse_dt(struct platform_device *pdev,
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct device_node *syscon_np;
u32 reg, bit;
int error;
- syscon_np = of_parse_phandle(np, "syscon", 0);
+ struct device_node *syscon_np __free(device_node) =
+ of_parse_phandle(np, "syscon", 0);
if (!syscon_np) {
dev_err(dev, "no syscon property\n");
return -ENODEV;
}
ts->regmap = syscon_node_to_regmap(syscon_np);
- of_node_put(syscon_np);
if (IS_ERR(ts->regmap)) {
dev_err(dev, "cannot get parent's regmap\n");
return PTR_ERR(ts->regmap);
diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c
index 575768b587bb..787f2caf4f73 100644
--- a/drivers/input/touchscreen/tsc2004.c
+++ b/drivers/input/touchscreen/tsc2004.c
@@ -42,13 +42,8 @@ static int tsc2004_probe(struct i2c_client *i2c)
tsc2004_cmd);
}
-static void tsc2004_remove(struct i2c_client *i2c)
-{
- tsc200x_remove(&i2c->dev);
-}
-
static const struct i2c_device_id tsc2004_idtable[] = {
- { "tsc2004", 0 },
+ { "tsc2004" },
{ }
};
MODULE_DEVICE_TABLE(i2c, tsc2004_idtable);
@@ -63,13 +58,13 @@ MODULE_DEVICE_TABLE(of, tsc2004_of_match);
static struct i2c_driver tsc2004_driver = {
.driver = {
- .name = "tsc2004",
- .of_match_table = of_match_ptr(tsc2004_of_match),
- .pm = &tsc200x_pm_ops,
+ .name = "tsc2004",
+ .dev_groups = tsc200x_groups,
+ .of_match_table = of_match_ptr(tsc2004_of_match),
+ .pm = pm_sleep_ptr(&tsc200x_pm_ops),
},
.id_table = tsc2004_idtable,
- .probe_new = tsc2004_probe,
- .remove = tsc2004_remove,
+ .probe = tsc2004_probe,
};
module_i2c_driver(tsc2004_driver);
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 555dfe98b3c4..6fe8b41b3ecc 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -64,11 +64,6 @@ static int tsc2005_probe(struct spi_device *spi)
tsc2005_cmd);
}
-static void tsc2005_remove(struct spi_device *spi)
-{
- tsc200x_remove(&spi->dev);
-}
-
#ifdef CONFIG_OF
static const struct of_device_id tsc2005_of_match[] = {
{ .compatible = "ti,tsc2005" },
@@ -79,12 +74,12 @@ MODULE_DEVICE_TABLE(of, tsc2005_of_match);
static struct spi_driver tsc2005_driver = {
.driver = {
- .name = "tsc2005",
- .of_match_table = of_match_ptr(tsc2005_of_match),
- .pm = &tsc200x_pm_ops,
+ .name = "tsc2005",
+ .dev_groups = tsc200x_groups,
+ .of_match_table = of_match_ptr(tsc2005_of_match),
+ .pm = pm_sleep_ptr(&tsc200x_pm_ops),
},
.probe = tsc2005_probe,
- .remove = tsc2005_remove,
};
module_spi_driver(tsc2005_driver);
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 69b08dd6c8df..e346fb4f7552 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -19,6 +19,7 @@
#ifndef _TSC2007_H
#define _TSC2007_H
+#include <linux/input/touchscreen.h>
struct gpio_desc;
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
@@ -63,6 +64,7 @@ struct tsc2007 {
struct i2c_client *client;
+ struct touchscreen_properties prop;
u16 model;
u16 x_plate_ohms;
u16 max_rt;
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 3c793fb70a0e..948935de894b 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_data/tsc2007.h>
@@ -68,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
{
- u32 rt = 0;
+ u64 rt = 0;
/* range filtering */
if (tc->x == MAX_12BIT)
@@ -79,11 +80,13 @@ u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
rt = tc->z2 - tc->z1;
rt *= tc->x;
rt *= tsc->x_plate_ohms;
- rt /= tc->z1;
+ rt = div_u64(rt, tc->z1);
rt = (rt + 2047) >> 12;
}
- return rt;
+ if (rt > U32_MAX)
+ return U32_MAX;
+ return (u32) rt;
}
bool tsc2007_is_pen_down(struct tsc2007 *ts)
@@ -142,8 +145,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
rt = ts->max_rt - rt;
input_report_key(input, BTN_TOUCH, 1);
- input_report_abs(input, ABS_X, tc.x);
- input_report_abs(input, ABS_Y, tc.y);
+ touchscreen_report_pos(input, &ts->prop, tc.x, tc.y, false);
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
@@ -172,26 +174,14 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
return IRQ_HANDLED;
}
-static irqreturn_t tsc2007_hard_irq(int irq, void *handle)
-{
- struct tsc2007 *ts = handle;
-
- if (tsc2007_is_pen_down(ts))
- return IRQ_WAKE_THREAD;
-
- if (ts->clear_penirq)
- ts->clear_penirq();
-
- return IRQ_HANDLED;
-}
-
static void tsc2007_stop(struct tsc2007 *ts)
{
ts->stopped = true;
mb();
wake_up(&ts->wait);
- disable_irq(ts->irq);
+ if (ts->irq)
+ disable_irq(ts->irq);
}
static int tsc2007_open(struct input_dev *input_dev)
@@ -202,7 +192,8 @@ static int tsc2007_open(struct input_dev *input_dev)
ts->stopped = false;
mb();
- enable_irq(ts->irq);
+ if (ts->irq)
+ enable_irq(ts->irq);
/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
@@ -226,7 +217,7 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct tsc2007 *ts = i2c_get_clientdata(client);
- return gpiod_get_value(ts->gpiod);
+ return gpiod_get_value_cansleep(ts->gpiod);
}
static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts)
@@ -267,7 +258,7 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts)
if (ts->gpiod)
ts->get_pendown_state = tsc2007_get_pendown_state_gpio;
else
- dev_warn(dev, "Pen down GPIO is not specified in properties\n");
+ dev_dbg(dev, "Pen down GPIO is not specified in properties\n");
return 0;
}
@@ -352,9 +343,9 @@ static int tsc2007_probe(struct i2c_client *client)
input_set_drvdata(input_dev, ts);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
-
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
+ touchscreen_parse_properties(input_dev, false, &ts->prop);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
ts->fuzzz, 0);
@@ -375,17 +366,19 @@ static int tsc2007_probe(struct i2c_client *client)
pdata->init_platform_hw();
}
- err = devm_request_threaded_irq(&client->dev, ts->irq,
- tsc2007_hard_irq, tsc2007_soft_irq,
- IRQF_ONESHOT,
- client->dev.driver->name, ts);
- if (err) {
- dev_err(&client->dev, "Failed to request irq %d: %d\n",
- ts->irq, err);
- return err;
- }
+ if (ts->irq) {
+ err = devm_request_threaded_irq(&client->dev, ts->irq,
+ NULL, tsc2007_soft_irq,
+ IRQF_ONESHOT,
+ client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to request irq %d: %d\n",
+ ts->irq, err);
+ return err;
+ }
- tsc2007_stop(ts);
+ tsc2007_stop(ts);
+ }
/* power down the chip (TSC2007_SETUP does not ACK on I2C) */
err = tsc2007_xfer(ts, PWRDOWN);
@@ -413,7 +406,7 @@ static int tsc2007_probe(struct i2c_client *client)
}
static const struct i2c_device_id tsc2007_idtable[] = {
- { "tsc2007", 0 },
+ { "tsc2007" },
{ }
};
@@ -431,7 +424,7 @@ static struct i2c_driver tsc2007_driver = {
.of_match_table = tsc2007_of_match,
},
.id_table = tsc2007_idtable,
- .probe_new = tsc2007_probe,
+ .probe = tsc2007_probe,
};
module_i2c_driver(tsc2007_driver);
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index 72c7258b93a5..eba53613b005 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -10,6 +10,7 @@
* based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -104,11 +105,11 @@ struct tsc200x {
bool pen_down;
- struct regulator *vio;
-
struct gpio_desc *reset_gpio;
int (*tsc200x_cmd)(struct device *dev, u8 cmd);
+
int irq;
+ bool wake_irq_enabled;
};
static void tsc200x_update_pen_state(struct tsc200x *ts,
@@ -136,7 +137,6 @@ static void tsc200x_update_pen_state(struct tsc200x *ts,
static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
{
struct tsc200x *ts = _ts;
- unsigned long flags;
unsigned int pressure;
struct tsc200x_data tsdata;
int error;
@@ -182,13 +182,11 @@ static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
if (unlikely(pressure > MAX_12BIT))
goto out;
- spin_lock_irqsave(&ts->lock, flags);
-
- tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
- mod_timer(&ts->penup_timer,
- jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
-
- spin_unlock_irqrestore(&ts->lock, flags);
+ scoped_guard(spinlock_irqsave, &ts->lock) {
+ tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
+ }
ts->last_valid_interrupt = jiffies;
out:
@@ -197,12 +195,10 @@ out:
static void tsc200x_penup_timer(struct timer_list *t)
{
- struct tsc200x *ts = from_timer(ts, t, penup_timer);
- unsigned long flags;
+ struct tsc200x *ts = timer_container_of(ts, t, penup_timer);
- spin_lock_irqsave(&ts->lock, flags);
+ guard(spinlock_irqsave)(&ts->lock);
tsc200x_update_pen_state(ts, 0, 0, 0);
- spin_unlock_irqrestore(&ts->lock, flags);
}
static void tsc200x_start_scan(struct tsc200x *ts)
@@ -232,12 +228,10 @@ static void __tsc200x_disable(struct tsc200x *ts)
{
tsc200x_stop_scan(ts);
- disable_irq(ts->irq);
- del_timer_sync(&ts->penup_timer);
+ guard(disable_irq)(&ts->irq);
+ timer_delete_sync(&ts->penup_timer);
cancel_delayed_work_sync(&ts->esd_work);
-
- enable_irq(ts->irq);
}
/* must be called with ts->mutex held */
@@ -253,80 +247,79 @@ static void __tsc200x_enable(struct tsc200x *ts)
}
}
-static ssize_t tsc200x_selftest_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+/*
+ * Test TSC200X communications via temp high register.
+ */
+static int tsc200x_do_selftest(struct tsc200x *ts)
{
- struct tsc200x *ts = dev_get_drvdata(dev);
- unsigned int temp_high;
unsigned int temp_high_orig;
unsigned int temp_high_test;
- bool success = true;
+ unsigned int temp_high;
int error;
- mutex_lock(&ts->mutex);
-
- /*
- * Test TSC200X communications via temp high register.
- */
- __tsc200x_disable(ts);
-
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high_orig);
if (error) {
- dev_warn(dev, "selftest failed: read error %d\n", error);
- success = false;
- goto out;
+ dev_warn(ts->dev, "selftest failed: read error %d\n", error);
+ return error;
}
temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
error = regmap_write(ts->regmap, TSC200X_REG_TEMP_HIGH, temp_high_test);
if (error) {
- dev_warn(dev, "selftest failed: write error %d\n", error);
- success = false;
- goto out;
+ dev_warn(ts->dev, "selftest failed: write error %d\n", error);
+ return error;
}
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
if (error) {
- dev_warn(dev, "selftest failed: read error %d after write\n",
- error);
- success = false;
- goto out;
- }
-
- if (temp_high != temp_high_test) {
- dev_warn(dev, "selftest failed: %d != %d\n",
- temp_high, temp_high_test);
- success = false;
+ dev_warn(ts->dev,
+ "selftest failed: read error %d after write\n", error);
+ return error;
}
/* hardware reset */
tsc200x_reset(ts);
- if (!success)
- goto out;
+ if (temp_high != temp_high_test) {
+ dev_warn(ts->dev, "selftest failed: %d != %d\n",
+ temp_high, temp_high_test);
+ return -EINVAL;
+ }
/* test that the reset really happened */
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
if (error) {
- dev_warn(dev, "selftest failed: read error %d after reset\n",
- error);
- success = false;
- goto out;
+ dev_warn(ts->dev,
+ "selftest failed: read error %d after reset\n", error);
+ return error;
}
if (temp_high != temp_high_orig) {
- dev_warn(dev, "selftest failed after reset: %d != %d\n",
+ dev_warn(ts->dev, "selftest failed after reset: %d != %d\n",
temp_high, temp_high_orig);
- success = false;
+ return -EINVAL;
}
-out:
- __tsc200x_enable(ts);
- mutex_unlock(&ts->mutex);
+ return 0;
+}
+
+static ssize_t tsc200x_selftest_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+ int error;
+
+ scoped_guard(mutex, &ts->mutex) {
+ __tsc200x_disable(ts);
+
+ error = tsc200x_do_selftest(ts);
+
+ __tsc200x_enable(ts);
+ }
- return sprintf(buf, "%d\n", success);
+ return sprintf(buf, "%d\n", !error);
}
static DEVICE_ATTR(selftest, S_IRUGO, tsc200x_selftest_show, NULL);
@@ -356,52 +349,54 @@ static const struct attribute_group tsc200x_attr_group = {
.attrs = tsc200x_attrs,
};
+const struct attribute_group *tsc200x_groups[] = {
+ &tsc200x_attr_group,
+ NULL
+};
+EXPORT_SYMBOL_GPL(tsc200x_groups);
+
static void tsc200x_esd_work(struct work_struct *work)
{
struct tsc200x *ts = container_of(work, struct tsc200x, esd_work.work);
int error;
unsigned int r;
- if (!mutex_trylock(&ts->mutex)) {
- /*
- * If the mutex is taken, it means that disable or enable is in
- * progress. In that case just reschedule the work. If the work
- * is not needed, it will be canceled by disable.
- */
- goto reschedule;
- }
-
- if (time_is_after_jiffies(ts->last_valid_interrupt +
- msecs_to_jiffies(ts->esd_timeout)))
- goto out;
-
- /* We should be able to read register without disabling interrupts. */
- error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
- if (!error &&
- !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
- goto out;
- }
-
/*
- * If we could not read our known value from configuration register 0
- * then we should reset the controller as if from power-up and start
- * scanning again.
+ * If the mutex is taken, it means that disable or enable is in
+ * progress. In that case just reschedule the work. If the work
+ * is not needed, it will be canceled by disable.
*/
- dev_info(ts->dev, "TSC200X not responding - resetting\n");
+ scoped_guard(mutex_try, &ts->mutex) {
+ if (time_is_after_jiffies(ts->last_valid_interrupt +
+ msecs_to_jiffies(ts->esd_timeout)))
+ break;
- disable_irq(ts->irq);
- del_timer_sync(&ts->penup_timer);
+ /*
+ * We should be able to read register without disabling
+ * interrupts.
+ */
+ error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
+ if (!error &&
+ !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
+ break;
+ }
- tsc200x_update_pen_state(ts, 0, 0, 0);
+ /*
+ * If we could not read our known value from configuration
+ * register 0 then we should reset the controller as if from
+ * power-up and start scanning again.
+ */
+ dev_info(ts->dev, "TSC200X not responding - resetting\n");
- tsc200x_reset(ts);
+ scoped_guard(disable_irq, &ts->irq) {
+ timer_delete_sync(&ts->penup_timer);
+ tsc200x_update_pen_state(ts, 0, 0, 0);
+ tsc200x_reset(ts);
+ }
- enable_irq(ts->irq);
- tsc200x_start_scan(ts);
+ tsc200x_start_scan(ts);
+ }
-out:
- mutex_unlock(&ts->mutex);
-reschedule:
/* re-arm the watchdog */
schedule_delayed_work(&ts->esd_work,
round_jiffies_relative(
@@ -412,15 +407,13 @@ static int tsc200x_open(struct input_dev *input)
{
struct tsc200x *ts = input_get_drvdata(input);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended)
__tsc200x_enable(ts);
ts->opened = true;
- mutex_unlock(&ts->mutex);
-
return 0;
}
@@ -428,14 +421,12 @@ static void tsc200x_close(struct input_dev *input)
{
struct tsc200x *ts = input_get_drvdata(input);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended)
__tsc200x_disable(ts);
ts->opened = false;
-
- mutex_unlock(&ts->mutex);
}
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
@@ -482,20 +473,6 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
&esd_timeout);
ts->esd_timeout = error ? 0 : esd_timeout;
- ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(ts->reset_gpio)) {
- error = PTR_ERR(ts->reset_gpio);
- dev_err(dev, "error acquiring reset gpio: %d\n", error);
- return error;
- }
-
- ts->vio = devm_regulator_get(dev, "vio");
- if (IS_ERR(ts->vio)) {
- error = PTR_ERR(ts->vio);
- dev_err(dev, "error acquiring vio regulator: %d", error);
- return error;
- }
-
mutex_init(&ts->mutex);
spin_lock_init(&ts->lock);
@@ -536,92 +513,84 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
touchscreen_parse_properties(input_dev, false, &ts->prop);
+ ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ error = PTR_ERR_OR_ZERO(ts->reset_gpio);
+ if (error) {
+ dev_err(dev, "error acquiring reset gpio: %d\n", error);
+ return error;
+ }
+
+ error = devm_regulator_get_enable(dev, "vio");
+ if (error) {
+ dev_err(dev, "error acquiring vio regulator: %d\n", error);
+ return error;
+ }
+
+ tsc200x_reset(ts);
+
/* Ensure the touchscreen is off */
tsc200x_stop_scan(ts);
- error = devm_request_threaded_irq(dev, irq, NULL,
- tsc200x_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "tsc200x", ts);
+ error = devm_request_threaded_irq(dev, irq, NULL, tsc200x_irq_thread,
+ IRQF_ONESHOT, "tsc200x", ts);
if (error) {
dev_err(dev, "Failed to request irq, err: %d\n", error);
return error;
}
- error = regulator_enable(ts->vio);
- if (error)
- return error;
-
dev_set_drvdata(dev, ts);
- error = sysfs_create_group(&dev->kobj, &tsc200x_attr_group);
- if (error) {
- dev_err(dev,
- "Failed to create sysfs attributes, err: %d\n", error);
- goto disable_regulator;
- }
error = input_register_device(ts->idev);
if (error) {
dev_err(dev,
"Failed to register input device, err: %d\n", error);
- goto err_remove_sysfs;
+ return error;
}
- irq_set_irq_wake(irq, 1);
- return 0;
+ device_init_wakeup(dev,
+ device_property_read_bool(dev, "wakeup-source"));
-err_remove_sysfs:
- sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
-disable_regulator:
- regulator_disable(ts->vio);
- return error;
+ return 0;
}
EXPORT_SYMBOL_GPL(tsc200x_probe);
-void tsc200x_remove(struct device *dev)
-{
- struct tsc200x *ts = dev_get_drvdata(dev);
-
- sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
-
- regulator_disable(ts->vio);
-}
-EXPORT_SYMBOL_GPL(tsc200x_remove);
-
-static int __maybe_unused tsc200x_suspend(struct device *dev)
+static int tsc200x_suspend(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended && ts->opened)
__tsc200x_disable(ts);
ts->suspended = true;
- mutex_unlock(&ts->mutex);
+ if (device_may_wakeup(dev))
+ ts->wake_irq_enabled = enable_irq_wake(ts->irq) == 0;
return 0;
}
-static int __maybe_unused tsc200x_resume(struct device *dev)
+static int tsc200x_resume(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
+
+ if (ts->wake_irq_enabled) {
+ disable_irq_wake(ts->irq);
+ ts->wake_irq_enabled = false;
+ }
if (ts->suspended && ts->opened)
__tsc200x_enable(ts);
ts->suspended = false;
- mutex_unlock(&ts->mutex);
-
return 0;
}
-SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
-EXPORT_SYMBOL_GPL(tsc200x_pm_ops);
+EXPORT_GPL_SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
MODULE_DESCRIPTION("TSC200x Touchscreen Driver Core");
diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h
index 4ded34425b21..e76ba7a889dd 100644
--- a/drivers/input/touchscreen/tsc200x-core.h
+++ b/drivers/input/touchscreen/tsc200x-core.h
@@ -70,10 +70,10 @@
extern const struct regmap_config tsc200x_regmap_config;
extern const struct dev_pm_ops tsc200x_pm_ops;
+extern const struct attribute_group *tsc200x_groups[];
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
struct regmap *regmap,
int (*tsc200x_cmd)(struct device *dev, u8 cmd));
-void tsc200x_remove(struct device *dev);
#endif
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index 139577021413..9f485cf57a72 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -83,7 +83,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
+ ptsc = kzalloc(sizeof(*ptsc), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ptsc || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
deleted file mode 100644
index dfd3b35590c3..000000000000
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Philips UCB1400 touchscreen driver
- *
- * Author: Nicolas Pitre
- * Created: September 25, 2006
- * Copyright: MontaVista Software, Inc.
- *
- * Spliting done by: Marek Vasut <marek.vasut@gmail.com>
- * If something doesn't work and it worked before spliting, e-mail me,
- * dont bother Nicolas please ;-)
- *
- * This code is heavily based on ucb1x00-*.c copyrighted by Russell King
- * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has
- * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/input.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/ucb1400.h>
-
-#define UCB1400_TS_POLL_PERIOD 10 /* ms */
-
-static bool adcsync;
-static int ts_delay = 55; /* us */
-static int ts_delay_pressure; /* us */
-
-/* Switch to interrupt mode. */
-static void ucb1400_ts_mode_int(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
- UCB_TS_CR_MODE_INT);
-}
-
-/*
- * Switch to pressure mode, and read pressure. We don't need to wait
- * here, since both plates are being driven.
- */
-static unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
-
- udelay(ts_delay_pressure);
-
- return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
-}
-
-/*
- * Switch to X position mode and measure Y plate. We switch the plate
- * configuration in pressure mode, then switch to position mode. This
- * gives a faster response time. Even so, we need to wait about 55us
- * for things to stabilise.
- */
-static unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-
- udelay(ts_delay);
-
- return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync);
-}
-
-/*
- * Switch to Y position mode and measure X plate. We switch the plate
- * configuration in pressure mode, then switch to position mode. This
- * gives a faster response time. Even so, we need to wait about 55us
- * for things to stabilise.
- */
-static int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
-
- udelay(ts_delay);
-
- return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync);
-}
-
-/*
- * Switch to X plate resistance mode. Set MX to ground, PX to
- * supply. Measure current.
- */
-static unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- return ucb1400_adc_read(ucb->ac97, 0, adcsync);
-}
-
-/*
- * Switch to Y plate resistance mode. Set MY to ground, PY to
- * supply. Measure current.
- */
-static unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR,
- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
- return ucb1400_adc_read(ucb->ac97, 0, adcsync);
-}
-
-static int ucb1400_ts_pen_up(struct ucb1400_ts *ucb)
-{
- unsigned short val = ucb1400_reg_read(ucb->ac97, UCB_TS_CR);
-
- return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW);
-}
-
-static void ucb1400_ts_irq_enable(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, UCB_IE_TSPX);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
- ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_TSPX);
-}
-
-static void ucb1400_ts_irq_disable(struct ucb1400_ts *ucb)
-{
- ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
-}
-
-static void ucb1400_ts_report_event(struct input_dev *idev, u16 pressure, u16 x, u16 y)
-{
- input_report_abs(idev, ABS_X, x);
- input_report_abs(idev, ABS_Y, y);
- input_report_abs(idev, ABS_PRESSURE, pressure);
- input_report_key(idev, BTN_TOUCH, 1);
- input_sync(idev);
-}
-
-static void ucb1400_ts_event_release(struct input_dev *idev)
-{
- input_report_abs(idev, ABS_PRESSURE, 0);
- input_report_key(idev, BTN_TOUCH, 0);
- input_sync(idev);
-}
-
-static void ucb1400_clear_pending_irq(struct ucb1400_ts *ucb)
-{
- unsigned int isr;
-
- isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
-
- if (isr & UCB_IE_TSPX)
- ucb1400_ts_irq_disable(ucb);
- else
- dev_dbg(&ucb->ts_idev->dev,
- "ucb1400: unexpected IE_STATUS = %#x\n", isr);
-}
-
-/*
- * A restriction with interrupts exists when using the ucb1400, as
- * the codec read/write routines may sleep while waiting for codec
- * access completion and uses semaphores for access control to the
- * AC97 bus. Therefore the driver is forced to use threaded interrupt
- * handler.
- */
-static irqreturn_t ucb1400_irq(int irqnr, void *devid)
-{
- struct ucb1400_ts *ucb = devid;
- unsigned int x, y, p;
-
- if (unlikely(irqnr != ucb->irq))
- return IRQ_NONE;
-
- ucb1400_clear_pending_irq(ucb);
-
- /* Start with a small delay before checking pendown state */
- msleep(UCB1400_TS_POLL_PERIOD);
-
- while (!ucb->stopped && !ucb1400_ts_pen_up(ucb)) {
- ucb1400_adc_enable(ucb->ac97);
- x = ucb1400_ts_read_xpos(ucb);
- y = ucb1400_ts_read_ypos(ucb);
- p = ucb1400_ts_read_pressure(ucb);
- ucb1400_adc_disable(ucb->ac97);
-
- ucb1400_ts_report_event(ucb->ts_idev, p, x, y);
-
- wait_event_timeout(ucb->ts_wait, ucb->stopped,
- msecs_to_jiffies(UCB1400_TS_POLL_PERIOD));
- }
-
- ucb1400_ts_event_release(ucb->ts_idev);
-
- if (!ucb->stopped) {
- /* Switch back to interrupt mode. */
- ucb1400_ts_mode_int(ucb);
- ucb1400_ts_irq_enable(ucb);
- }
-
- return IRQ_HANDLED;
-}
-
-static void ucb1400_ts_stop(struct ucb1400_ts *ucb)
-{
- /* Signal IRQ thread to stop polling and disable the handler. */
- ucb->stopped = true;
- mb();
- wake_up(&ucb->ts_wait);
- disable_irq(ucb->irq);
-
- ucb1400_ts_irq_disable(ucb);
- ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0);
-}
-
-/* Must be called with ts->lock held */
-static void ucb1400_ts_start(struct ucb1400_ts *ucb)
-{
- /* Tell IRQ thread that it may poll the device. */
- ucb->stopped = false;
- mb();
-
- ucb1400_ts_mode_int(ucb);
- ucb1400_ts_irq_enable(ucb);
-
- enable_irq(ucb->irq);
-}
-
-static int ucb1400_ts_open(struct input_dev *idev)
-{
- struct ucb1400_ts *ucb = input_get_drvdata(idev);
-
- ucb1400_ts_start(ucb);
-
- return 0;
-}
-
-static void ucb1400_ts_close(struct input_dev *idev)
-{
- struct ucb1400_ts *ucb = input_get_drvdata(idev);
-
- ucb1400_ts_stop(ucb);
-}
-
-#ifndef NO_IRQ
-#define NO_IRQ 0
-#endif
-
-/*
- * Try to probe our interrupt, rather than relying on lots of
- * hard-coded machine dependencies.
- */
-static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb,
- struct platform_device *pdev)
-{
- unsigned long mask, timeout;
-
- mask = probe_irq_on();
-
- /* Enable the ADC interrupt. */
- ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC);
- ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
-
- /* Cause an ADC interrupt. */
- ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA);
- ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
-
- /* Wait for the conversion to complete. */
- timeout = jiffies + HZ/2;
- while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) &
- UCB_ADC_DAT_VALID)) {
- cpu_relax();
- if (time_after(jiffies, timeout)) {
- dev_err(&pdev->dev, "timed out in IRQ probe\n");
- probe_irq_off(mask);
- return -ENODEV;
- }
- }
- ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0);
-
- /* Disable and clear interrupt. */
- ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0);
- ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff);
- ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0);
-
- /* Read triggered interrupt. */
- ucb->irq = probe_irq_off(mask);
- if (ucb->irq < 0 || ucb->irq == NO_IRQ)
- return -ENODEV;
-
- return 0;
-}
-
-static int ucb1400_ts_probe(struct platform_device *pdev)
-{
- struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);
- int error, x_res, y_res;
- u16 fcsr;
-
- ucb->ts_idev = input_allocate_device();
- if (!ucb->ts_idev) {
- error = -ENOMEM;
- goto err;
- }
-
- /* Only in case the IRQ line wasn't supplied, try detecting it */
- if (ucb->irq < 0) {
- error = ucb1400_ts_detect_irq(ucb, pdev);
- if (error) {
- dev_err(&pdev->dev, "IRQ probe failed\n");
- goto err_free_devs;
- }
- }
- dev_dbg(&pdev->dev, "found IRQ %d\n", ucb->irq);
-
- init_waitqueue_head(&ucb->ts_wait);
-
- input_set_drvdata(ucb->ts_idev, ucb);
-
- ucb->ts_idev->dev.parent = &pdev->dev;
- ucb->ts_idev->name = "UCB1400 touchscreen interface";
- ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97,
- AC97_VENDOR_ID1);
- ucb->ts_idev->id.product = ucb->id;
- ucb->ts_idev->open = ucb1400_ts_open;
- ucb->ts_idev->close = ucb1400_ts_close;
- ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY);
- ucb->ts_idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- /*
- * Enable ADC filter to prevent horrible jitter on Colibri.
- * This also further reduces jitter on boards where ADCSYNC
- * pin is connected.
- */
- fcsr = ucb1400_reg_read(ucb->ac97, UCB_FCSR);
- ucb1400_reg_write(ucb->ac97, UCB_FCSR, fcsr | UCB_FCSR_AVE);
-
- ucb1400_adc_enable(ucb->ac97);
- x_res = ucb1400_ts_read_xres(ucb);
- y_res = ucb1400_ts_read_yres(ucb);
- ucb1400_adc_disable(ucb->ac97);
- dev_dbg(&pdev->dev, "x/y = %d/%d\n", x_res, y_res);
-
- input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0);
- input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0);
- input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0);
-
- ucb1400_ts_stop(ucb);
-
- error = request_threaded_irq(ucb->irq, NULL, ucb1400_irq,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "UCB1400", ucb);
- if (error) {
- dev_err(&pdev->dev,
- "unable to grab irq%d: %d\n", ucb->irq, error);
- goto err_free_devs;
- }
-
- error = input_register_device(ucb->ts_idev);
- if (error)
- goto err_free_irq;
-
- return 0;
-
-err_free_irq:
- free_irq(ucb->irq, ucb);
-err_free_devs:
- input_free_device(ucb->ts_idev);
-err:
- return error;
-}
-
-static int ucb1400_ts_remove(struct platform_device *pdev)
-{
- struct ucb1400_ts *ucb = dev_get_platdata(&pdev->dev);
-
- free_irq(ucb->irq, ucb);
- input_unregister_device(ucb->ts_idev);
-
- return 0;
-}
-
-static int __maybe_unused ucb1400_ts_suspend(struct device *dev)
-{
- struct ucb1400_ts *ucb = dev_get_platdata(dev);
- struct input_dev *idev = ucb->ts_idev;
-
- mutex_lock(&idev->mutex);
-
- if (input_device_enabled(idev))
- ucb1400_ts_stop(ucb);
-
- mutex_unlock(&idev->mutex);
- return 0;
-}
-
-static int __maybe_unused ucb1400_ts_resume(struct device *dev)
-{
- struct ucb1400_ts *ucb = dev_get_platdata(dev);
- struct input_dev *idev = ucb->ts_idev;
-
- mutex_lock(&idev->mutex);
-
- if (input_device_enabled(idev))
- ucb1400_ts_start(ucb);
-
- mutex_unlock(&idev->mutex);
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(ucb1400_ts_pm_ops,
- ucb1400_ts_suspend, ucb1400_ts_resume);
-
-static struct platform_driver ucb1400_ts_driver = {
- .probe = ucb1400_ts_probe,
- .remove = ucb1400_ts_remove,
- .driver = {
- .name = "ucb1400_ts",
- .pm = &ucb1400_ts_pm_ops,
- },
-};
-module_platform_driver(ucb1400_ts_driver);
-
-module_param(adcsync, bool, 0444);
-MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
-
-module_param(ts_delay, int, 0444);
-MODULE_PARM_DESC(ts_delay, "Delay between panel setup and"
- " position read. Default = 55us.");
-
-module_param(ts_delay_pressure, int, 0444);
-MODULE_PARM_DESC(ts_delay_pressure,
- "delay between panel setup and pressure read."
- " Default = 0us.");
-
-MODULE_DESCRIPTION("Philips UCB1400 touchscreen driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index d6d04b9f04fc..7567efabe014 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -68,8 +68,6 @@ struct usbtouch_device_info {
*/
bool irq_always;
- void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
-
/*
* used to get the packet len. possible return values:
* > 0: packet len
@@ -94,7 +92,7 @@ struct usbtouch_usb {
struct urb *irq;
struct usb_interface *interface;
struct input_dev *input;
- struct usbtouch_device_info *type;
+ const struct usbtouch_device_info *type;
struct mutex pm_mutex; /* serialize access to open/suspend */
bool is_open;
char name[128];
@@ -103,141 +101,8 @@ struct usbtouch_usb {
int x, y;
int touch, press;
-};
-
-/* device types */
-enum {
- DEVTYPE_IGNORE = -1,
- DEVTYPE_EGALAX,
- DEVTYPE_PANJIT,
- DEVTYPE_3M,
- DEVTYPE_ITM,
- DEVTYPE_ETURBO,
- DEVTYPE_GUNZE,
- DEVTYPE_DMC_TSC10,
- DEVTYPE_IRTOUCH,
- DEVTYPE_IRTOUCH_HIRES,
- DEVTYPE_IDEALTEK,
- DEVTYPE_GENERAL_TOUCH,
- DEVTYPE_GOTOP,
- DEVTYPE_JASTEC,
- DEVTYPE_E2I,
- DEVTYPE_ZYTRONIC,
- DEVTYPE_TC45USB,
- DEVTYPE_NEXIO,
- DEVTYPE_ELO,
- DEVTYPE_ETOUCH,
-};
-
-#define USB_DEVICE_HID_CLASS(vend, prod) \
- .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
- | USB_DEVICE_ID_MATCH_DEVICE, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = USB_INTERFACE_CLASS_HID
-
-static const struct usb_device_id usbtouch_devices[] = {
-#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
- /* ignore the HID capable devices, handled by usbhid */
- {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
- {USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
-
- /* normal device IDs */
- {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
- {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_3M
- {USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ITM
- {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
- {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
- {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
- {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
- {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
- {USB_DEVICE(0x255e, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x6615, 0x0012), .driver_info = DEVTYPE_IRTOUCH_HIRES},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
- {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
- {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
- {USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
- {USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
- {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
- {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_E2I
- {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
- {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
- /* TC5UH */
- {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
- /* TC4UM */
- {USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
- /* data interface only */
- {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
- .driver_info = DEVTYPE_NEXIO},
- {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
- .driver_info = DEVTYPE_NEXIO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ELO
- {USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
- {USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
-#endif
-
- {}
+ void (*process_pkt)(struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
};
@@ -273,6 +138,16 @@ static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info e2i_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 6,
+ .init = e2i_init,
+ .read_data = e2i_read_data,
+};
#endif
@@ -292,9 +167,8 @@ static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int egalax_init(struct usbtouch_usb *usbtouch)
{
- int ret, i;
- unsigned char *buf;
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+ int ret, i;
/*
* An eGalax diagnostic packet kicks the device into using the right
@@ -302,7 +176,7 @@ static int egalax_init(struct usbtouch_usb *usbtouch)
* read later and ignored.
*/
- buf = kmalloc(3, GFP_KERNEL);
+ u8 *buf __free(kfree) = kmalloc(3, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -316,17 +190,11 @@ static int egalax_init(struct usbtouch_usb *usbtouch)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, buf, 3,
USB_CTRL_SET_TIMEOUT);
- if (ret >= 0) {
- ret = 0;
- break;
- }
if (ret != -EPIPE)
break;
}
- kfree(buf);
-
- return ret;
+ return ret < 0 ? ret : 0;
}
static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
@@ -356,6 +224,17 @@ static int egalax_get_pkt_len(unsigned char *buf, int len)
return 0;
}
+
+static const struct usbtouch_device_info egalax_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .get_pkt_len = egalax_get_pkt_len,
+ .read_data = egalax_read_data,
+ .init = egalax_init,
+};
#endif
/*****************************************************************************
@@ -402,6 +281,16 @@ static int etouch_get_pkt_len(unsigned char *buf, int len)
return 0;
}
+
+static const struct usbtouch_device_info etouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .get_pkt_len = etouch_get_pkt_len,
+ .read_data = etouch_read_data,
+};
#endif
/*****************************************************************************
@@ -416,6 +305,15 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info panjit_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .read_data = panjit_read_data,
+};
#endif
@@ -449,35 +347,13 @@ struct mtouch_priv {
u8 fw_rev_minor;
};
-static ssize_t mtouch_firmware_rev_show(struct device *dev,
- struct device_attribute *attr, char *output)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- struct mtouch_priv *priv = usbtouch->priv;
-
- return scnprintf(output, PAGE_SIZE, "%1x.%1x\n",
- priv->fw_rev_major, priv->fw_rev_minor);
-}
-static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
-
-static struct attribute *mtouch_attrs[] = {
- &dev_attr_firmware_rev.attr,
- NULL
-};
-
-static const struct attribute_group mtouch_attr_group = {
- .attrs = mtouch_attrs,
-};
-
static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
{
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
struct mtouch_priv *priv = usbtouch->priv;
- u8 *buf;
int ret;
- buf = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO);
+ u8 *buf __free(kfree) = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO);
if (!buf)
return -ENOMEM;
@@ -489,36 +365,24 @@ static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
if (ret != MTOUCHUSB_REQ_CTRLLR_ID_LEN) {
dev_warn(&usbtouch->interface->dev,
"Failed to read FW rev: %d\n", ret);
- ret = ret < 0 ? ret : -EIO;
- goto free;
+ return ret < 0 ? ret : -EIO;
}
priv->fw_rev_major = buf[3];
priv->fw_rev_minor = buf[4];
- ret = 0;
-
-free:
- kfree(buf);
- return ret;
+ return 0;
}
static int mtouch_alloc(struct usbtouch_usb *usbtouch)
{
- int ret;
+ struct mtouch_priv *priv;
- usbtouch->priv = kmalloc(sizeof(struct mtouch_priv), GFP_KERNEL);
- if (!usbtouch->priv)
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- ret = sysfs_create_group(&usbtouch->interface->dev.kobj,
- &mtouch_attr_group);
- if (ret) {
- kfree(usbtouch->priv);
- usbtouch->priv = NULL;
- return ret;
- }
-
+ usbtouch->priv = priv;
return 0;
}
@@ -569,9 +433,53 @@ static void mtouch_exit(struct usbtouch_usb *usbtouch)
{
struct mtouch_priv *priv = usbtouch->priv;
- sysfs_remove_group(&usbtouch->interface->dev.kobj, &mtouch_attr_group);
kfree(priv);
}
+
+static struct usbtouch_device_info mtouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x4000,
+ .min_yc = 0x0,
+ .max_yc = 0x4000,
+ .rept_size = 11,
+ .read_data = mtouch_read_data,
+ .alloc = mtouch_alloc,
+ .init = mtouch_init,
+ .exit = mtouch_exit,
+};
+
+static ssize_t mtouch_firmware_rev_show(struct device *dev,
+ struct device_attribute *attr, char *output)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+ struct mtouch_priv *priv = usbtouch->priv;
+
+ return sysfs_emit(output, "%1x.%1x\n",
+ priv->fw_rev_major, priv->fw_rev_minor);
+}
+static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
+
+static struct attribute *mtouch_attrs[] = {
+ &dev_attr_firmware_rev.attr,
+ NULL
+};
+
+static bool mtouch_group_visible(struct kobject *kobj)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+ return usbtouch->type == &mtouch_dev_info;
+}
+
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(mtouch);
+
+static const struct attribute_group mtouch_attr_group = {
+ .is_visible = SYSFS_GROUP_VISIBLE(mtouch),
+ .attrs = mtouch_attrs,
+};
#endif
@@ -606,6 +514,16 @@ static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info itm_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .max_press = 0xff,
+ .rept_size = 8,
+ .read_data = itm_read_data,
+};
#endif
@@ -640,6 +558,16 @@ static int eturbo_get_pkt_len(unsigned char *buf, int len)
return 3;
return 0;
}
+
+static const struct usbtouch_device_info eturbo_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 8,
+ .get_pkt_len = eturbo_get_pkt_len,
+ .read_data = eturbo_read_data,
+};
#endif
@@ -658,6 +586,15 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info gunze_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = gunze_read_data,
+};
#endif
/*****************************************************************************
@@ -686,24 +623,23 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
{
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
- int ret = -ENOMEM;
- unsigned char *buf;
+ int ret;
- buf = kmalloc(2, GFP_NOIO);
+ u8 *buf __free(kfree) = kmalloc(2, GFP_NOIO);
if (!buf)
- goto err_nobuf;
+ return -ENOMEM;
+
/* reset */
buf[0] = buf[1] = 0xFF;
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
- TSC10_CMD_RESET,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+ TSC10_CMD_RESET,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- goto err_out;
- if (buf[0] != 0x06) {
- ret = -ENODEV;
- goto err_out;
- }
+ return ret;
+
+ if (buf[0] != 0x06)
+ return -ENODEV;
/* TSC-25 data sheet specifies a delay after the RESET command */
msleep(150);
@@ -711,28 +647,22 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
/* set coordinate output rate */
buf[0] = buf[1] = 0xFF;
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
- TSC10_CMD_RATE,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+ TSC10_CMD_RATE,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- goto err_out;
- if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
- ret = -ENODEV;
- goto err_out;
- }
+ return ret;
+
+ if (buf[0] != 0x06 && (buf[0] != 0x15 || buf[1] != 0x01))
+ return -ENODEV;
/* start sending data */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- TSC10_CMD_DATA1,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-err_out:
- kfree(buf);
-err_nobuf:
- return ret;
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ TSC10_CMD_DATA1,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
-
static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
@@ -741,6 +671,16 @@ static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info dmc_tsc10_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 5,
+ .init = dmc_tsc10_init,
+ .read_data = dmc_tsc10_read_data,
+};
#endif
@@ -756,6 +696,24 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info irtouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .read_data = irtouch_read_data,
+};
+
+static const struct usbtouch_device_info irtouch_hires_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 8,
+ .read_data = irtouch_read_data,
+};
#endif
/*****************************************************************************
@@ -770,6 +728,15 @@ static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info tc45usb_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 5,
+ .read_data = tc45usb_read_data,
+};
#endif
/*****************************************************************************
@@ -809,6 +776,16 @@ static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 0;
}
}
+
+static const struct usbtouch_device_info idealtek_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .get_pkt_len = idealtek_get_pkt_len,
+ .read_data = idealtek_read_data,
+};
#endif
/*****************************************************************************
@@ -824,6 +801,15 @@ static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info general_touch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 7,
+ .read_data = general_touch_read_data,
+};
#endif
/*****************************************************************************
@@ -838,6 +824,15 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info gotop_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 4,
+ .read_data = gotop_read_data,
+};
#endif
/*****************************************************************************
@@ -852,6 +847,15 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info jastec_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = jastec_read_data,
+};
#endif
/*****************************************************************************
@@ -888,6 +892,16 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 0;
}
+
+static const struct usbtouch_device_info zytronic_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 5,
+ .read_data = zytronic_read_data,
+ .irq_always = true,
+};
#endif
/*****************************************************************************
@@ -924,12 +938,11 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch)
struct nexio_priv *priv;
int ret = -ENOMEM;
- usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
- if (!usbtouch->priv)
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
goto out_buf;
- priv = usbtouch->priv;
-
+ usbtouch->priv = priv;
priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
GFP_KERNEL);
if (!priv->ack_buf)
@@ -959,7 +972,6 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
struct nexio_priv *priv = usbtouch->priv;
int ret = -ENOMEM;
int actual_len, i;
- unsigned char *buf;
char *firmware_ver = NULL, *device_name = NULL;
int input_ep = 0, output_ep = 0;
@@ -975,9 +987,9 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
if (!input_ep || !output_ep)
return -ENXIO;
- buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
+ u8 *buf __free(kfree) = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
if (!buf)
- goto out_buf;
+ return -ENOMEM;
/* two empty reads */
for (i = 0; i < 2; i++) {
@@ -985,7 +997,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
buf, NEXIO_BUFSIZE, &actual_len,
NEXIO_TIMEOUT);
if (ret < 0)
- goto out_buf;
+ return ret;
}
/* send init command */
@@ -994,7 +1006,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
buf, sizeof(nexio_init_pkt), &actual_len,
NEXIO_TIMEOUT);
if (ret < 0)
- goto out_buf;
+ return ret;
/* read replies */
for (i = 0; i < 3; i++) {
@@ -1025,11 +1037,8 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
priv->ack_buf, sizeof(nexio_ack_pkt),
nexio_ack_complete, usbtouch);
- ret = 0;
-out_buf:
- kfree(buf);
- return ret;
+ return 0;
}
static void nexio_exit(struct usbtouch_usb *usbtouch)
@@ -1066,13 +1075,11 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
if (ret)
dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
- if (!usbtouch->type->max_xc) {
- usbtouch->type->max_xc = 2 * x_len;
+ if (!input_abs_get_max(usbtouch->input, ABS_X)) {
input_set_abs_params(usbtouch->input, ABS_X,
- 0, usbtouch->type->max_xc, 0, 0);
- usbtouch->type->max_yc = 2 * y_len;
+ 0, 2 * x_len, 0, 0);
input_set_abs_params(usbtouch->input, ABS_Y,
- 0, usbtouch->type->max_yc, 0, 0);
+ 0, 2 * y_len, 0, 0);
}
/*
* The device reports state of IR sensors on X and Y axes.
@@ -1127,6 +1134,15 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
}
return 0;
}
+
+static const struct usbtouch_device_info nexio_dev_info = {
+ .rept_size = 1024,
+ .irq_always = true,
+ .read_data = nexio_read_data,
+ .alloc = nexio_alloc,
+ .init = nexio_init,
+ .exit = nexio_exit,
+};
#endif
@@ -1145,241 +1161,17 @@ static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
-#endif
-
-
-/*****************************************************************************
- * the different device descriptors
- */
-#ifdef MULTI_PACKET
-static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
- unsigned char *pkt, int len);
-#endif
-
-static struct usbtouch_device_info usbtouch_dev_info[] = {
-#ifdef CONFIG_TOUCHSCREEN_USB_ELO
- [DEVTYPE_ELO] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .max_press = 0xff,
- .rept_size = 8,
- .read_data = elo_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
- [DEVTYPE_EGALAX] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 16,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = egalax_get_pkt_len,
- .read_data = egalax_read_data,
- .init = egalax_init,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
- [DEVTYPE_PANJIT] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .read_data = panjit_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_3M
- [DEVTYPE_3M] = {
- .min_xc = 0x0,
- .max_xc = 0x4000,
- .min_yc = 0x0,
- .max_yc = 0x4000,
- .rept_size = 11,
- .read_data = mtouch_read_data,
- .alloc = mtouch_alloc,
- .init = mtouch_init,
- .exit = mtouch_exit,
- },
-#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_ITM
- [DEVTYPE_ITM] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .max_press = 0xff,
- .rept_size = 8,
- .read_data = itm_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
- [DEVTYPE_ETURBO] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 8,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = eturbo_get_pkt_len,
- .read_data = eturbo_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
- [DEVTYPE_GUNZE] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 4,
- .read_data = gunze_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
- [DEVTYPE_DMC_TSC10] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 5,
- .init = dmc_tsc10_init,
- .read_data = dmc_tsc10_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
- [DEVTYPE_IRTOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .read_data = irtouch_read_data,
- },
-
- [DEVTYPE_IRTOUCH_HIRES] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 8,
- .read_data = irtouch_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
- [DEVTYPE_IDEALTEK] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = idealtek_get_pkt_len,
- .read_data = idealtek_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
- [DEVTYPE_GENERAL_TOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 7,
- .read_data = general_touch_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
- [DEVTYPE_GOTOP] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 4,
- .read_data = gotop_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
- [DEVTYPE_JASTEC] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 4,
- .read_data = jastec_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_E2I
- [DEVTYPE_E2I] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 6,
- .init = e2i_init,
- .read_data = e2i_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
- [DEVTYPE_ZYTRONIC] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 5,
- .read_data = zytronic_read_data,
- .irq_always = true,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
- [DEVTYPE_TC45USB] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 5,
- .read_data = tc45usb_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
- [DEVTYPE_NEXIO] = {
- .rept_size = 1024,
- .irq_always = true,
- .read_data = nexio_read_data,
- .alloc = nexio_alloc,
- .init = nexio_init,
- .exit = nexio_exit,
- },
-#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
- [DEVTYPE_ETOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 16,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = etouch_get_pkt_len,
- .read_data = etouch_read_data,
- },
-#endif
+static const struct usbtouch_device_info elo_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .max_press = 0xff,
+ .rept_size = 8,
+ .read_data = elo_read_data,
};
+#endif
/*****************************************************************************
@@ -1388,10 +1180,10 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len)
{
- struct usbtouch_device_info *type = usbtouch->type;
+ const struct usbtouch_device_info *type = usbtouch->type;
if (!type->read_data(usbtouch, pkt))
- return;
+ return;
input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
@@ -1484,9 +1276,15 @@ out_flush_buf:
usbtouch->buf_len = 0;
return;
}
+#else
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ unsigned char *pkt, int len)
+{
+ dev_WARN_ONCE(&usbtouch->interface->dev, 1,
+ "Protocol has ->get_pkt_len() without #define MULTI_PACKET");
+}
#endif
-
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
@@ -1517,7 +1315,7 @@ static void usbtouch_irq(struct urb *urb)
goto exit;
}
- usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
+ usbtouch->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
@@ -1527,6 +1325,20 @@ exit:
__func__, retval);
}
+static int usbtouch_start_io(struct usbtouch_usb *usbtouch)
+{
+ guard(mutex)(&usbtouch->pm_mutex);
+
+ if (!usbtouch->type->irq_always)
+ if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
+ return -EIO;
+
+ usbtouch->interface->needs_remote_wakeup = 1;
+ usbtouch->is_open = true;
+
+ return 0;
+}
+
static int usbtouch_open(struct input_dev *input)
{
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
@@ -1535,23 +1347,12 @@ static int usbtouch_open(struct input_dev *input)
usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
- if (r < 0)
- goto out;
-
- mutex_lock(&usbtouch->pm_mutex);
- if (!usbtouch->type->irq_always) {
- if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
- r = -EIO;
- goto out_put;
- }
- }
+ if (r)
+ return r;
+
+ r = usbtouch_start_io(usbtouch);
- usbtouch->interface->needs_remote_wakeup = 1;
- usbtouch->is_open = true;
-out_put:
- mutex_unlock(&usbtouch->pm_mutex);
usb_autopm_put_interface(usbtouch->interface);
-out:
return r;
}
@@ -1560,11 +1361,11 @@ static void usbtouch_close(struct input_dev *input)
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
int r;
- mutex_lock(&usbtouch->pm_mutex);
- if (!usbtouch->type->irq_always)
- usb_kill_urb(usbtouch->irq);
- usbtouch->is_open = false;
- mutex_unlock(&usbtouch->pm_mutex);
+ scoped_guard(mutex, &usbtouch->pm_mutex) {
+ if (!usbtouch->type->irq_always)
+ usb_kill_urb(usbtouch->irq);
+ usbtouch->is_open = false;
+ }
r = usb_autopm_get_interface(usbtouch->interface);
usbtouch->interface->needs_remote_wakeup = 0;
@@ -1572,8 +1373,7 @@ static void usbtouch_close(struct input_dev *input)
usb_autopm_put_interface(usbtouch->interface);
}
-static int usbtouch_suspend
-(struct usb_interface *intf, pm_message_t message)
+static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
@@ -1585,20 +1385,19 @@ static int usbtouch_suspend
static int usbtouch_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- int result = 0;
- mutex_lock(&usbtouch->pm_mutex);
+ guard(mutex)(&usbtouch->pm_mutex);
+
if (usbtouch->is_open || usbtouch->type->irq_always)
- result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&usbtouch->pm_mutex);
+ return usb_submit_urb(usbtouch->irq, GFP_NOIO);
- return result;
+ return 0;
}
static int usbtouch_reset_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- int err = 0;
+ int err;
/* reinit the device */
if (usbtouch->type->init) {
@@ -1612,12 +1411,12 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
}
/* restart IO if needed */
- mutex_lock(&usbtouch->pm_mutex);
+ guard(mutex)(&usbtouch->pm_mutex);
+
if (usbtouch->is_open)
- err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&usbtouch->pm_mutex);
+ return usb_submit_urb(usbtouch->irq, GFP_NOIO);
- return err;
+ return 0;
}
static void usbtouch_free_buffers(struct usb_device *udev,
@@ -1647,31 +1446,25 @@ static int usbtouch_probe(struct usb_interface *intf,
struct input_dev *input_dev;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
- struct usbtouch_device_info *type;
+ const struct usbtouch_device_info *type;
int err = -ENOMEM;
/* some devices are ignored */
- if (id->driver_info == DEVTYPE_IGNORE)
- return -ENODEV;
-
- if (id->driver_info >= ARRAY_SIZE(usbtouch_dev_info))
+ type = (const struct usbtouch_device_info *)id->driver_info;
+ if (!type)
return -ENODEV;
endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
if (!endpoint)
return -ENXIO;
- usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
+ usbtouch = kzalloc(sizeof(*usbtouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!usbtouch || !input_dev)
goto out_free;
mutex_init(&usbtouch->pm_mutex);
-
- type = &usbtouch_dev_info[id->driver_info];
usbtouch->type = type;
- if (!type->process_pkt)
- type->process_pkt = usbtouch_process_pkt;
usbtouch->data_size = type->rept_size;
if (type->get_pkt_len) {
@@ -1695,6 +1488,9 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
if (!usbtouch->buffer)
goto out_free_buffers;
+ usbtouch->process_pkt = usbtouch_process_multi;
+ } else {
+ usbtouch->process_pkt = usbtouch_process_pkt;
}
usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
@@ -1841,6 +1637,150 @@ static void usbtouch_disconnect(struct usb_interface *intf)
kfree(usbtouch);
}
+static const struct attribute_group *usbtouch_groups[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+ &mtouch_attr_group,
+#endif
+ NULL
+};
+
+static const struct usb_device_id usbtouch_devices[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+ /* ignore the HID capable devices, handled by usbhid */
+ { USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0001, USB_INTERFACE_CLASS_HID),
+ .driver_info = 0 },
+ { USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0002, USB_INTERFACE_CLASS_HID),
+ .driver_info = 0 },
+
+ /* normal device IDs */
+ { USB_DEVICE(0x3823, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x3823, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0123, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0eef, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0eef, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x1234, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x1234, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
+ { USB_DEVICE(0x134c, 0x0001),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0002),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0003),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0004),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+ { USB_DEVICE(0x0596, 0x0001),
+ .driver_info = (kernel_ulong_t)&mtouch_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ITM
+ { USB_DEVICE(0x0403, 0xf9e9),
+ .driver_info = (kernel_ulong_t)&itm_dev_info },
+ { USB_DEVICE(0x16e3, 0xf9e9),
+ .driver_info = (kernel_ulong_t)&itm_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+ { USB_DEVICE(0x1234, 0x5678),
+ .driver_info = (kernel_ulong_t)&eturbo_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
+ { USB_DEVICE(0x0637, 0x0001),
+ .driver_info = (kernel_ulong_t)&gunze_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
+ { USB_DEVICE(0x0afa, 0x03e8),
+ .driver_info = (kernel_ulong_t)&dmc_tsc10_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+ { USB_DEVICE(0x255e, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x595a, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x6615, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x6615, 0x0012),
+ .driver_info = (kernel_ulong_t)&irtouch_hires_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ { USB_DEVICE(0x1391, 0x1000),
+ .driver_info = (kernel_ulong_t)&idealtek_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ { USB_DEVICE(0x0dfc, 0x0001),
+ .driver_info = (kernel_ulong_t)&general_touch_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+ { USB_DEVICE(0x08f2, 0x007f),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+ { USB_DEVICE(0x08f2, 0x00ce),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+ { USB_DEVICE(0x08f2, 0x00f4),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+ { USB_DEVICE(0x0f92, 0x0001),
+ .driver_info = (kernel_ulong_t)&jastec_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+ { USB_DEVICE(0x1ac7, 0x0001),
+ .driver_info = (kernel_ulong_t)&e2i_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+ { USB_DEVICE(0x14c8, 0x0003),
+ .driver_info = (kernel_ulong_t)&zytronic_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+ /* TC5UH */
+ { USB_DEVICE(0x0664, 0x0309),
+ .driver_info = (kernel_ulong_t)&tc45usb_dev_info },
+ /* TC4UM */
+ { USB_DEVICE(0x0664, 0x0306),
+ .driver_info = (kernel_ulong_t)&tc45usb_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+ /* data interface only */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+ .driver_info = (kernel_ulong_t)&nexio_dev_info },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+ .driver_info = (kernel_ulong_t)&nexio_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ELO
+ { USB_DEVICE(0x04e7, 0x0020),
+ .driver_info = (kernel_ulong_t)&elo_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+ { USB_DEVICE(0x7374, 0x0001),
+ .driver_info = (kernel_ulong_t)&etouch_dev_info },
+#endif
+
+ { }
+};
MODULE_DEVICE_TABLE(usb, usbtouch_devices);
static struct usb_driver usbtouch_driver = {
@@ -1851,6 +1791,7 @@ static struct usb_driver usbtouch_driver = {
.resume = usbtouch_resume,
.reset_resume = usbtouch_reset_resume,
.id_table = usbtouch_devices,
+ .dev_groups = usbtouch_groups,
.supports_autosuspend = 1,
};
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index c9188ee00c62..fd97a83f5664 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Bitmasks (for data[3]) */
#define WACOM_TIP_SWITCH BIT(0)
@@ -232,7 +232,7 @@ static int wacom_i2c_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused wacom_i2c_suspend(struct device *dev)
+static int wacom_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -241,7 +241,7 @@ static int __maybe_unused wacom_i2c_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wacom_i2c_resume(struct device *dev)
+static int wacom_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -250,21 +250,21 @@ static int __maybe_unused wacom_i2c_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
static const struct i2c_device_id wacom_i2c_id[] = {
- { "WAC_I2C_EMR", 0 },
- { },
+ { "WAC_I2C_EMR" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
static struct i2c_driver wacom_i2c_driver = {
.driver = {
.name = "wacom_i2c",
- .pm = &wacom_i2c_pm,
+ .pm = pm_sleep_ptr(&wacom_i2c_pm),
},
- .probe_new = wacom_i2c_probe,
+ .probe = wacom_i2c_probe,
.id_table = wacom_i2c_id,
};
module_i2c_driver(wacom_i2c_driver);
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 928c5ee3ac36..ed2ca8a689d5 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -380,30 +380,28 @@ static int w8001_open(struct input_dev *dev)
struct w8001 *w8001 = input_get_drvdata(dev);
int err;
- err = mutex_lock_interruptible(&w8001->mutex);
- if (err)
- return err;
+ scoped_guard(mutex_intr, &w8001->mutex) {
+ if (w8001->open_count == 0) {
+ err = w8001_command(w8001, W8001_CMD_START, false);
+ if (err)
+ return err;
+ }
- if (w8001->open_count++ == 0) {
- err = w8001_command(w8001, W8001_CMD_START, false);
- if (err)
- w8001->open_count--;
+ w8001->open_count++;
+ return 0;
}
- mutex_unlock(&w8001->mutex);
- return err;
+ return -EINTR;
}
static void w8001_close(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
- mutex_lock(&w8001->mutex);
+ guard(mutex)(&w8001->mutex);
if (--w8001->open_count == 0)
w8001_command(w8001, W8001_CMD_STOP, false);
-
- mutex_unlock(&w8001->mutex);
}
static int w8001_detect(struct w8001 *w8001)
@@ -595,10 +593,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
struct w8001 *w8001;
struct input_dev *input_dev_pen;
struct input_dev *input_dev_touch;
- char basename[64];
+ char basename[64] = "Wacom Serial";
int err, err_pen, err_touch;
- w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
+ w8001 = kzalloc(sizeof(*w8001), GFP_KERNEL);
input_dev_pen = input_allocate_device();
input_dev_touch = input_allocate_device();
if (!w8001 || !input_dev_pen || !input_dev_touch) {
@@ -625,8 +623,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
/* For backwards-compatibility we compose the basename based on
* capabilities and then just append the tool type
*/
- strscpy(basename, "Wacom Serial", sizeof(basename));
-
err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
if (err_pen && err_touch) {
@@ -635,8 +631,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
if (!err_pen) {
- strscpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
- strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
+ snprintf(w8001->pen_name, sizeof(w8001->pen_name),
+ "%s Pen", basename);
input_dev_pen->name = w8001->pen_name;
w8001_set_devdata(input_dev_pen, w8001, serio);
@@ -651,9 +647,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
if (!err_touch) {
- strscpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
- strlcat(w8001->touch_name, " Finger",
- sizeof(w8001->touch_name));
+ snprintf(w8001->touch_name, sizeof(w8001->touch_name),
+ "%s Finger", basename);
input_dev_touch->name = w8001->touch_name;
w8001_set_devdata(input_dev_touch, w8001, serio);
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c
index 3f87db5cdca4..88d376090e6e 100644
--- a/drivers/input/touchscreen/wdt87xx_i2c.c
+++ b/drivers/input/touchscreen/wdt87xx_i2c.c
@@ -20,7 +20,7 @@
#include <linux/firmware.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
@@ -887,7 +887,7 @@ static ssize_t config_csum_show(struct device *dev,
cfg_csum = wdt->param.xmls_id1;
cfg_csum = (cfg_csum << 16) | wdt->param.xmls_id2;
- return scnprintf(buf, PAGE_SIZE, "%x\n", cfg_csum);
+ return sysfs_emit(buf, "%x\n", cfg_csum);
}
static ssize_t fw_version_show(struct device *dev,
@@ -896,7 +896,7 @@ static ssize_t fw_version_show(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
- return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.fw_id);
+ return sysfs_emit(buf, "%x\n", wdt->param.fw_id);
}
static ssize_t plat_id_show(struct device *dev,
@@ -905,7 +905,7 @@ static ssize_t plat_id_show(struct device *dev,
struct i2c_client *client = to_i2c_client(dev);
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
- return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.plat_id);
+ return sysfs_emit(buf, "%x\n", wdt->param.plat_id);
}
static ssize_t update_config_store(struct device *dev,
@@ -944,10 +944,7 @@ static struct attribute *wdt87xx_attrs[] = {
&dev_attr_update_fw.attr,
NULL
};
-
-static const struct attribute_group wdt87xx_attr_group = {
- .attrs = wdt87xx_attrs,
-};
+ATTRIBUTE_GROUPS(wdt87xx);
static void wdt87xx_report_contact(struct input_dev *input,
struct wdt87xx_sys_param *param,
@@ -1104,16 +1101,10 @@ static int wdt87xx_ts_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
- if (error) {
- dev_err(&client->dev, "create sysfs failed: %d\n", error);
- return error;
- }
-
return 0;
}
-static int __maybe_unused wdt87xx_suspend(struct device *dev)
+static int wdt87xx_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int error;
@@ -1132,7 +1123,7 @@ static int __maybe_unused wdt87xx_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wdt87xx_resume(struct device *dev)
+static int wdt87xx_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
int error;
@@ -1154,26 +1145,29 @@ static int __maybe_unused wdt87xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
static const struct i2c_device_id wdt87xx_dev_id[] = {
- { WDT87XX_NAME, 0 },
+ { WDT87XX_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id);
+#ifdef CONFIG_ACPI
static const struct acpi_device_id wdt87xx_acpi_id[] = {
{ "WDHT0001", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
+#endif
static struct i2c_driver wdt87xx_driver = {
- .probe_new = wdt87xx_ts_probe,
+ .probe = wdt87xx_ts_probe,
.id_table = wdt87xx_dev_id,
.driver = {
- .name = WDT87XX_NAME,
- .pm = &wdt87xx_pm_ops,
+ .name = WDT87XX_NAME,
+ .dev_groups = wdt87xx_groups,
+ .pm = pm_sleep_ptr(&wdt87xx_pm_ops),
.acpi_match_table = ACPI_PTR(wdt87xx_acpi_id),
},
};
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 319f57fb9af5..98f8ec408cad 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -374,14 +374,12 @@ err_alloc:
return error;
}
-static int wm831x_ts_remove(struct platform_device *pdev)
+static void wm831x_ts_remove(struct platform_device *pdev)
{
struct wm831x_ts *wm831x_ts = platform_get_drvdata(pdev);
free_irq(wm831x_ts->pd_irq, wm831x_ts);
free_irq(wm831x_ts->data_irq, wm831x_ts);
-
- return 0;
}
static struct platform_driver wm831x_ts_driver = {
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index 4b55d5e1ea0f..96484aae030c 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index 6947714dfefa..087ece57741a 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index a67fbe304f92..6f13f46ce6e6 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index f51ab5614532..96354c44af87 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -29,6 +29,7 @@
* - Support for async sampling control for noisy LCDs.
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -222,7 +223,7 @@ EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
/*
* Codec GPIO pin configuration, this sets pin direction, polarity,
- * stickyness and wake up.
+ * stickiness and wake up.
*/
void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky,
@@ -403,7 +404,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
* is actively working with the touchscreen we
* don't want to lose the quick response. So we
* will slowly increase sleep time after the
- * pen is up and quicky restore it to ~one task
+ * pen is up and quickly restore it to ~one task
* switch when pen is down again.
*/
if (wm->ts_reader_interval < HZ / 10)
@@ -756,14 +757,12 @@ batt_err:
return ret;
}
-static int wm97xx_mfd_remove(struct platform_device *pdev)
+static void wm97xx_mfd_remove(struct platform_device *pdev)
{
wm97xx_remove(&pdev->dev);
-
- return 0;
}
-static int __maybe_unused wm97xx_suspend(struct device *dev)
+static int wm97xx_suspend(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
u16 reg;
@@ -797,7 +796,7 @@ static int __maybe_unused wm97xx_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused wm97xx_resume(struct device *dev)
+static int wm97xx_resume(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
@@ -833,7 +832,7 @@ static int __maybe_unused wm97xx_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
/*
* Machine specific operations
@@ -869,13 +868,13 @@ static struct device_driver wm97xx_driver = {
.owner = THIS_MODULE,
.probe = wm97xx_probe,
.remove = wm97xx_remove,
- .pm = &wm97xx_pm_ops,
+ .pm = pm_sleep_ptr(&wm97xx_pm_ops),
};
static struct platform_driver wm97xx_mfd_driver = {
.driver = {
.name = "wm97xx-ts",
- .pm = &wm97xx_pm_ops,
+ .pm = pm_sleep_ptr(&wm97xx_pm_ops),
},
.probe = wm97xx_mfd_probe,
.remove = wm97xx_mfd_remove,
diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c
index bfa0c637d569..943634ba9cd9 100644
--- a/drivers/input/touchscreen/zet6223.c
+++ b/drivers/input/touchscreen/zet6223.c
@@ -11,7 +11,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ZET6223_MAX_FINGERS 16
#define ZET6223_MAX_PKT_SIZE (3 + 4 * ZET6223_MAX_FINGERS)
@@ -25,8 +25,6 @@
struct zet6223_ts {
struct i2c_client *client;
struct input_dev *input;
- struct regulator *vcc;
- struct regulator *vio;
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
u16 max_x;
@@ -238,7 +236,7 @@ static const struct of_device_id zet6223_of_match[] = {
MODULE_DEVICE_TABLE(of, zet6223_of_match);
static const struct i2c_device_id zet6223_id[] = {
- { "zet6223", 0},
+ { "zet6223" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zet6223_id);
@@ -248,7 +246,7 @@ static struct i2c_driver zet6223_driver = {
.name = "zet6223",
.of_match_table = zet6223_of_match,
},
- .probe_new = zet6223_probe,
+ .probe = zet6223_probe,
.id_table = zet6223_id
};
module_i2c_driver(zet6223_driver);
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index 24e78ca83fa3..df42fdf36ae3 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -9,20 +9,20 @@
* Author: Pieter Truter<ptruter@intrinsyc.com>
*/
-#include <linux/module.h>
-#include <linux/hrtimer.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
#include <linux/device.h>
-#include <linux/sysfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
#include <linux/input/mt.h>
-#include <linux/platform_data/zforce_ts.h>
-#include <linux/regulator/consumer.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
@@ -96,9 +96,7 @@ struct zforce_point {
* @suspending in the process of going to suspend (don't emit wakeup
* events for commands executed to suspend the device)
* @suspended device suspended
- * @access_mutex serialize i2c-access, to keep multipart reads together
* @command_done completion to wait for the command result
- * @command_mutex serialize commands sent to the ic
* @command_waiting the id of the command that is currently waiting
* for a result
* @command_result returned result of the command
@@ -106,11 +104,9 @@ struct zforce_point {
struct zforce_ts {
struct i2c_client *client;
struct input_dev *input;
- const struct zforce_ts_platdata *pdata;
+ struct touchscreen_properties prop;
char phys[32];
- struct regulator *reg_vdd;
-
struct gpio_desc *gpio_int;
struct gpio_desc *gpio_rst;
@@ -124,10 +120,7 @@ struct zforce_ts {
u16 version_build;
u16 version_rev;
- struct mutex access_mutex;
-
struct completion command_done;
- struct mutex command_mutex;
int command_waiting;
int command_result;
};
@@ -144,9 +137,7 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd)
buf[1] = 1; /* data size, command only */
buf[2] = cmd;
- mutex_lock(&ts->access_mutex);
ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf));
- mutex_unlock(&ts->access_mutex);
if (ret < 0) {
dev_err(&client->dev, "i2c send data request error: %d\n", ret);
return ret;
@@ -155,59 +146,36 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd)
return 0;
}
-static void zforce_reset_assert(struct zforce_ts *ts)
-{
- gpiod_set_value_cansleep(ts->gpio_rst, 1);
-}
-
-static void zforce_reset_deassert(struct zforce_ts *ts)
-{
- gpiod_set_value_cansleep(ts->gpio_rst, 0);
-}
-
static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len)
{
struct i2c_client *client = ts->client;
int ret;
- ret = mutex_trylock(&ts->command_mutex);
- if (!ret) {
- dev_err(&client->dev, "already waiting for a command\n");
- return -EBUSY;
- }
-
dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n",
buf[1], buf[2]);
ts->command_waiting = buf[2];
- mutex_lock(&ts->access_mutex);
ret = i2c_master_send(client, buf, len);
- mutex_unlock(&ts->access_mutex);
if (ret < 0) {
dev_err(&client->dev, "i2c send data request error: %d\n", ret);
- goto unlock;
+ return ret;
}
dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]);
- if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) {
- ret = -ETIME;
- goto unlock;
- }
+ if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
+ return -ETIME;
ret = ts->command_result;
-
-unlock:
- mutex_unlock(&ts->command_mutex);
- return ret;
+ return 0;
}
static int zforce_command_wait(struct zforce_ts *ts, u8 cmd)
{
struct i2c_client *client = ts->client;
char buf[3];
- int ret;
+ int error;
dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd);
@@ -215,10 +183,11 @@ static int zforce_command_wait(struct zforce_ts *ts, u8 cmd)
buf[1] = 1; /* data size, command only */
buf[2] = cmd;
- ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
- if (ret < 0) {
- dev_err(&client->dev, "i2c send data request error: %d\n", ret);
- return ret;
+ error = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+ if (error) {
+ dev_err(&client->dev, "i2c send data request error: %d\n",
+ error);
+ return error;
}
return 0;
@@ -266,41 +235,40 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
static int zforce_start(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
- const struct zforce_ts_platdata *pdata = ts->pdata;
- int ret;
+ int error;
dev_dbg(&client->dev, "starting device\n");
- ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
- if (ret) {
- dev_err(&client->dev, "Unable to initialize, %d\n", ret);
- return ret;
+ error = zforce_command_wait(ts, COMMAND_INITIALIZE);
+ if (error) {
+ dev_err(&client->dev, "Unable to initialize, %d\n", error);
+ return error;
}
- ret = zforce_resolution(ts, pdata->x_max, pdata->y_max);
- if (ret) {
- dev_err(&client->dev, "Unable to set resolution, %d\n", ret);
- goto error;
+ error = zforce_resolution(ts, ts->prop.max_x, ts->prop.max_y);
+ if (error) {
+ dev_err(&client->dev, "Unable to set resolution, %d\n", error);
+ goto err_deactivate;
}
- ret = zforce_scan_frequency(ts, 10, 50, 50);
- if (ret) {
+ error = zforce_scan_frequency(ts, 10, 50, 50);
+ if (error) {
dev_err(&client->dev, "Unable to set scan frequency, %d\n",
- ret);
- goto error;
+ error);
+ goto err_deactivate;
}
- ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH);
- if (ret) {
+ error = zforce_setconfig(ts, SETCONFIG_DUALTOUCH);
+ if (error) {
dev_err(&client->dev, "Unable to set config\n");
- goto error;
+ goto err_deactivate;
}
/* start sending touch events */
- ret = zforce_command(ts, COMMAND_DATAREQUEST);
- if (ret) {
+ error = zforce_command(ts, COMMAND_DATAREQUEST);
+ if (error) {
dev_err(&client->dev, "Unable to request data\n");
- goto error;
+ goto err_deactivate;
}
/*
@@ -311,24 +279,24 @@ static int zforce_start(struct zforce_ts *ts)
return 0;
-error:
+err_deactivate:
zforce_command_wait(ts, COMMAND_DEACTIVATE);
- return ret;
+ return error;
}
static int zforce_stop(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
- int ret;
+ int error;
dev_dbg(&client->dev, "stopping device\n");
/* Deactivates touch sensing and puts the device into sleep. */
- ret = zforce_command_wait(ts, COMMAND_DEACTIVATE);
- if (ret != 0) {
+ error = zforce_command_wait(ts, COMMAND_DEACTIVATE);
+ if (error) {
dev_err(&client->dev, "could not deactivate device, %d\n",
- ret);
- return ret;
+ error);
+ return error;
}
return 0;
@@ -337,9 +305,9 @@ static int zforce_stop(struct zforce_ts *ts)
static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
{
struct i2c_client *client = ts->client;
- const struct zforce_ts_platdata *pdata = ts->pdata;
struct zforce_point point;
int count, i, num = 0;
+ u8 *p;
count = payload[0];
if (count > ZFORCE_REPORT_POINTS) {
@@ -350,30 +318,28 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
}
for (i = 0; i < count; i++) {
- point.coord_x =
- payload[9 * i + 2] << 8 | payload[9 * i + 1];
- point.coord_y =
- payload[9 * i + 4] << 8 | payload[9 * i + 3];
+ p = &payload[i * 9 + 1];
+
+ point.coord_x = get_unaligned_le16(&p[0]);
+ point.coord_y = get_unaligned_le16(&p[2]);
- if (point.coord_x > pdata->x_max ||
- point.coord_y > pdata->y_max) {
+ if (point.coord_x > ts->prop.max_x ||
+ point.coord_y > ts->prop.max_y) {
dev_warn(&client->dev, "coordinates (%d,%d) invalid\n",
point.coord_x, point.coord_y);
point.coord_x = point.coord_y = 0;
}
- point.state = payload[9 * i + 5] & 0x0f;
- point.id = (payload[9 * i + 5] & 0xf0) >> 4;
+ point.state = p[4] & 0x0f;
+ point.id = (p[4] & 0xf0) >> 4;
/* determine touch major, minor and orientation */
- point.area_major = max(payload[9 * i + 6],
- payload[9 * i + 7]);
- point.area_minor = min(payload[9 * i + 6],
- payload[9 * i + 7]);
- point.orientation = payload[9 * i + 6] > payload[9 * i + 7];
+ point.area_major = max(p[5], p[6]);
+ point.area_minor = min(p[5], p[6]);
+ point.orientation = p[5] > p[6];
- point.pressure = payload[9 * i + 8];
- point.prblty = payload[9 * i + 9];
+ point.pressure = p[7];
+ point.prblty = p[8];
dev_dbg(&client->dev,
"point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n",
@@ -386,14 +352,11 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
/* the zforce id starts with "1", so needs to be decreased */
input_mt_slot(ts->input, point.id - 1);
- input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,
- point.state != STATE_UP);
-
- if (point.state != STATE_UP) {
- input_report_abs(ts->input, ABS_MT_POSITION_X,
- point.coord_x);
- input_report_abs(ts->input, ABS_MT_POSITION_Y,
- point.coord_y);
+ if (input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,
+ point.state != STATE_UP)) {
+ touchscreen_report_pos(ts->input, &ts->prop,
+ point.coord_x, point.coord_y,
+ true);
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
point.area_major);
input_report_abs(ts->input, ABS_MT_TOUCH_MINOR,
@@ -418,41 +381,35 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
struct i2c_client *client = ts->client;
int ret;
- mutex_lock(&ts->access_mutex);
-
/* read 2 byte message header */
ret = i2c_master_recv(client, buf, 2);
if (ret < 0) {
dev_err(&client->dev, "error reading header: %d\n", ret);
- goto unlock;
+ return ret;
}
if (buf[PAYLOAD_HEADER] != FRAME_START) {
dev_err(&client->dev, "invalid frame start: %d\n", buf[0]);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
if (buf[PAYLOAD_LENGTH] == 0) {
dev_err(&client->dev, "invalid payload length: %d\n",
buf[PAYLOAD_LENGTH]);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
/* read the message */
ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]);
if (ret < 0) {
dev_err(&client->dev, "error reading payload: %d\n", ret);
- goto unlock;
+ return ret;
}
dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n",
buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]);
-unlock:
- mutex_unlock(&ts->access_mutex);
- return ret;
+ return 0;
}
static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
@@ -483,9 +440,10 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
- int ret;
+ int error;
u8 payload_buffer[FRAME_MAXSIZE];
u8 *payload;
+ bool suspending;
/*
* When still suspended, return.
@@ -499,7 +457,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
dev_dbg(&client->dev, "handling interrupt\n");
/* Don't emit wakeup events from commands run by zforce_suspend */
- if (!ts->suspending && device_may_wakeup(&client->dev))
+ suspending = READ_ONCE(ts->suspending);
+ if (!suspending && device_may_wakeup(&client->dev))
pm_stay_awake(&client->dev);
/*
@@ -512,10 +471,10 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* no IRQ any more)
*/
do {
- ret = zforce_read_packet(ts, payload_buffer);
- if (ret < 0) {
+ error = zforce_read_packet(ts, payload_buffer);
+ if (error) {
dev_err(&client->dev,
- "could not read packet, ret: %d\n", ret);
+ "could not read packet, ret: %d\n", error);
break;
}
@@ -527,7 +486,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* Always report touch-events received while
* suspending, when being a wakeup source
*/
- if (ts->suspending && device_may_wakeup(&client->dev))
+ if (suspending && device_may_wakeup(&client->dev))
pm_wakeup_event(&client->dev, 500);
zforce_touch_event(ts, &payload[RESPONSE_DATA]);
break;
@@ -551,14 +510,15 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* Version Payload Results
* [2:major] [2:minor] [2:build] [2:rev]
*/
- ts->version_major = (payload[RESPONSE_DATA + 1] << 8) |
- payload[RESPONSE_DATA];
- ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) |
- payload[RESPONSE_DATA + 2];
- ts->version_build = (payload[RESPONSE_DATA + 5] << 8) |
- payload[RESPONSE_DATA + 4];
- ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) |
- payload[RESPONSE_DATA + 6];
+ ts->version_major =
+ get_unaligned_le16(&payload[RESPONSE_DATA]);
+ ts->version_minor =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 2]);
+ ts->version_build =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 4]);
+ ts->version_rev =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 6]);
+
dev_dbg(&ts->client->dev,
"Firmware Version %04x:%04x %04x:%04x\n",
ts->version_major, ts->version_minor,
@@ -580,7 +540,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
}
} while (gpiod_get_value_cansleep(ts->gpio_int));
- if (!ts->suspending && device_may_wakeup(&client->dev))
+ if (!suspending && device_may_wakeup(&client->dev))
pm_relax(&client->dev);
dev_dbg(&client->dev, "finished interrupt\n");
@@ -599,24 +559,20 @@ static void zforce_input_close(struct input_dev *dev)
{
struct zforce_ts *ts = input_get_drvdata(dev);
struct i2c_client *client = ts->client;
- int ret;
+ int error;
- ret = zforce_stop(ts);
- if (ret)
+ error = zforce_stop(ts);
+ if (error)
dev_warn(&client->dev, "stopping zforce failed\n");
-
- return;
}
-static int __maybe_unused zforce_suspend(struct device *dev)
+static int __zforce_suspend(struct zforce_ts *ts)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct zforce_ts *ts = i2c_get_clientdata(client);
+ struct i2c_client *client = ts->client;
struct input_dev *input = ts->input;
- int ret = 0;
+ int error;
- mutex_lock(&input->mutex);
- ts->suspending = true;
+ guard(mutex)(&input->mutex);
/*
* When configured as a wakeup source device should always wake
@@ -627,9 +583,9 @@ static int __maybe_unused zforce_suspend(struct device *dev)
/* Need to start device, if not open, to be a wakeup source. */
if (!input_device_enabled(input)) {
- ret = zforce_start(ts);
- if (ret)
- goto unlock;
+ error = zforce_start(ts);
+ if (error)
+ return error;
}
enable_irq_wake(client->irq);
@@ -637,30 +593,42 @@ static int __maybe_unused zforce_suspend(struct device *dev)
dev_dbg(&client->dev,
"suspend without being a wakeup source\n");
- ret = zforce_stop(ts);
- if (ret)
- goto unlock;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
disable_irq(client->irq);
}
ts->suspended = true;
+ return 0;
+}
-unlock:
- ts->suspending = false;
- mutex_unlock(&input->mutex);
+static int zforce_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct zforce_ts *ts = i2c_get_clientdata(client);
+ int ret;
+
+ WRITE_ONCE(ts->suspending, true);
+ smp_mb();
+
+ ret = __zforce_suspend(ts);
+
+ smp_mb();
+ WRITE_ONCE(ts->suspending, false);
return ret;
}
-static int __maybe_unused zforce_resume(struct device *dev)
+static int zforce_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct zforce_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
- int ret = 0;
+ int error;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
ts->suspended = false;
@@ -671,79 +639,50 @@ static int __maybe_unused zforce_resume(struct device *dev)
/* need to stop device if it was not open on suspend */
if (!input_device_enabled(input)) {
- ret = zforce_stop(ts);
- if (ret)
- goto unlock;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
}
} else if (input_device_enabled(input)) {
dev_dbg(&client->dev, "resume without being a wakeup source\n");
enable_irq(client->irq);
- ret = zforce_start(ts);
- if (ret < 0)
- goto unlock;
+ error = zforce_start(ts);
+ if (error)
+ return error;
}
-unlock:
- mutex_unlock(&input->mutex);
-
- return ret;
+ return 0;
}
-static SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
static void zforce_reset(void *data)
{
struct zforce_ts *ts = data;
- zforce_reset_assert(ts);
-
+ gpiod_set_value_cansleep(ts->gpio_rst, 1);
udelay(10);
-
- if (!IS_ERR(ts->reg_vdd))
- regulator_disable(ts->reg_vdd);
}
-static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
+static void zforce_ts_parse_legacy_properties(struct zforce_ts *ts)
{
- struct zforce_ts_platdata *pdata;
- struct device_node *np = dev->of_node;
-
- if (!np)
- return ERR_PTR(-ENOENT);
+ u32 x_max = 0;
+ u32 y_max = 0;
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "failed to allocate platform data\n");
- return ERR_PTR(-ENOMEM);
- }
-
- if (of_property_read_u32(np, "x-size", &pdata->x_max)) {
- dev_err(dev, "failed to get x-size property\n");
- return ERR_PTR(-EINVAL);
- }
+ device_property_read_u32(&ts->client->dev, "x-size", &x_max);
+ input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, x_max, 0, 0);
- if (of_property_read_u32(np, "y-size", &pdata->y_max)) {
- dev_err(dev, "failed to get y-size property\n");
- return ERR_PTR(-EINVAL);
- }
-
- return pdata;
+ device_property_read_u32(&ts->client->dev, "y-size", &y_max);
+ input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, y_max, 0, 0);
}
static int zforce_probe(struct i2c_client *client)
{
- const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
struct zforce_ts *ts;
struct input_dev *input_dev;
- int ret;
-
- if (!pdata) {
- pdata = zforce_parse_dt(&client->dev);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- }
+ int error;
ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
if (!ts)
@@ -751,22 +690,18 @@ static int zforce_probe(struct i2c_client *client)
ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(ts->gpio_rst)) {
- ret = PTR_ERR(ts->gpio_rst);
- dev_err(&client->dev,
- "failed to request reset GPIO: %d\n", ret);
- return ret;
- }
+ error = PTR_ERR_OR_ZERO(ts->gpio_rst);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request reset GPIO\n");
if (ts->gpio_rst) {
ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq",
GPIOD_IN);
- if (IS_ERR(ts->gpio_int)) {
- ret = PTR_ERR(ts->gpio_int);
- dev_err(&client->dev,
- "failed to request interrupt GPIO: %d\n", ret);
- return ret;
- }
+ error = PTR_ERR_OR_ZERO(ts->gpio_int);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request interrupt GPIO\n");
} else {
/*
* Deprecated GPIO handling for compatibility
@@ -776,66 +711,45 @@ static int zforce_probe(struct i2c_client *client)
/* INT GPIO */
ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0,
GPIOD_IN);
- if (IS_ERR(ts->gpio_int)) {
- ret = PTR_ERR(ts->gpio_int);
- dev_err(&client->dev,
- "failed to request interrupt GPIO: %d\n", ret);
- return ret;
- }
+
+ error = PTR_ERR_OR_ZERO(ts->gpio_int);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request interrupt GPIO\n");
/* RST GPIO */
ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1,
GPIOD_OUT_HIGH);
- if (IS_ERR(ts->gpio_rst)) {
- ret = PTR_ERR(ts->gpio_rst);
- dev_err(&client->dev,
- "failed to request reset GPIO: %d\n", ret);
- return ret;
- }
- }
-
- ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
- if (IS_ERR(ts->reg_vdd)) {
- ret = PTR_ERR(ts->reg_vdd);
- if (ret == -EPROBE_DEFER)
- return ret;
- } else {
- ret = regulator_enable(ts->reg_vdd);
- if (ret)
- return ret;
-
- /*
- * according to datasheet add 100us grace time after regular
- * regulator enable delay.
- */
- udelay(100);
+ error = PTR_ERR_OR_ZERO(ts->gpio_rst);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request reset GPIO\n");
}
- ret = devm_add_action(&client->dev, zforce_reset, ts);
- if (ret) {
- dev_err(&client->dev, "failed to register reset action, %d\n",
- ret);
+ error = devm_regulator_get_enable(&client->dev, "vdd");
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request vdd supply\n");
- /* hereafter the regulator will be disabled by the action */
- if (!IS_ERR(ts->reg_vdd))
- regulator_disable(ts->reg_vdd);
+ /*
+ * According to datasheet add 100us grace time after regular
+ * regulator enable delay.
+ */
+ usleep_range(100, 200);
- return ret;
- }
+ error = devm_add_action_or_reset(&client->dev, zforce_reset, ts);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to register reset action\n");
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev = devm_input_allocate_device(&client->dev);
- if (!input_dev) {
- dev_err(&client->dev, "could not allocate input device\n");
- return -ENOMEM;
- }
-
- mutex_init(&ts->access_mutex);
- mutex_init(&ts->command_mutex);
+ if (!input_dev)
+ return dev_err_probe(&client->dev, -ENOMEM,
+ "could not allocate input device\n");
- ts->pdata = pdata;
ts->client = client;
ts->input = input_dev;
@@ -846,22 +760,21 @@ static int zforce_probe(struct i2c_client *client)
input_dev->open = zforce_input_open;
input_dev->close = zforce_input_close;
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(EV_SYN, input_dev->evbit);
- __set_bit(EV_ABS, input_dev->evbit);
-
- /* For multi touch */
- input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
- pdata->x_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
- pdata->y_max, 0, 0);
+ zforce_ts_parse_legacy_properties(ts);
+ touchscreen_parse_properties(input_dev, true, &ts->prop);
+ if (ts->prop.max_x == 0 || ts->prop.max_y == 0)
+ return dev_err_probe(&client->dev, -EINVAL, "no size specified");
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ZFORCE_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
ZFORCE_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
- input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT);
+
+ error = input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS,
+ INPUT_MT_DIRECT);
+ if (error)
+ return error;
input_set_drvdata(ts->input, ts);
@@ -874,58 +787,52 @@ static int zforce_probe(struct i2c_client *client)
* Therefore we can trigger the interrupt anytime it is low and do
* not need to limit it to the interrupt edge.
*/
- ret = devm_request_threaded_irq(&client->dev, client->irq,
- zforce_irq, zforce_irq_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- input_dev->name, ts);
- if (ret) {
- dev_err(&client->dev, "irq %d request failed\n", client->irq);
- return ret;
- }
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ zforce_irq, zforce_irq_thread,
+ IRQF_ONESHOT, input_dev->name, ts);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "irq %d request failed\n", client->irq);
i2c_set_clientdata(client, ts);
/* let the controller boot */
- zforce_reset_deassert(ts);
+ gpiod_set_value_cansleep(ts->gpio_rst, 0);
ts->command_waiting = NOTIFICATION_BOOTCOMPLETE;
if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
dev_warn(&client->dev, "bootcomplete timed out\n");
/* need to start device to get version information */
- ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
- if (ret) {
- dev_err(&client->dev, "unable to initialize, %d\n", ret);
- return ret;
- }
+ error = zforce_command_wait(ts, COMMAND_INITIALIZE);
+ if (error)
+ return dev_err_probe(&client->dev, error, "unable to initialize\n");
/* this gets the firmware version among other information */
- ret = zforce_command_wait(ts, COMMAND_STATUS);
- if (ret < 0) {
- dev_err(&client->dev, "couldn't get status, %d\n", ret);
+ error = zforce_command_wait(ts, COMMAND_STATUS);
+ if (error) {
+ dev_err_probe(&client->dev, error, "couldn't get status\n");
zforce_stop(ts);
- return ret;
+ return error;
}
/* stop device and put it into sleep until it is opened */
- ret = zforce_stop(ts);
- if (ret < 0)
- return ret;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
device_set_wakeup_capable(&client->dev, true);
- ret = input_register_device(input_dev);
- if (ret) {
- dev_err(&client->dev, "could not register input device, %d\n",
- ret);
- return ret;
- }
+ error = input_register_device(input_dev);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "could not register input device\n");
return 0;
}
-static struct i2c_device_id zforce_idtable[] = {
- { "zforce-ts", 0 },
+static const struct i2c_device_id zforce_idtable[] = {
+ { "zforce-ts" },
{ }
};
MODULE_DEVICE_TABLE(i2c, zforce_idtable);
@@ -941,10 +848,11 @@ MODULE_DEVICE_TABLE(of, zforce_dt_idtable);
static struct i2c_driver zforce_driver = {
.driver = {
.name = "zforce-ts",
- .pm = &zforce_pm_ops,
+ .pm = pm_sleep_ptr(&zforce_pm_ops),
.of_match_table = of_match_ptr(zforce_dt_idtable),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
- .probe_new = zforce_probe,
+ .probe = zforce_probe,
.id_table = zforce_idtable,
};
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 52f9e9eaab14..716d6fa60f86 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -34,7 +35,13 @@
#define ZINITIX_DEBUG_REG 0x0115 /* 0~7 */
#define ZINITIX_TOUCH_MODE 0x0010
+
#define ZINITIX_CHIP_REVISION 0x0011
+#define ZINITIX_CHIP_BTX0X_MASK 0xF0F0
+#define ZINITIX_CHIP_BT4X2 0x4020
+#define ZINITIX_CHIP_BT4X3 0x4030
+#define ZINITIX_CHIP_BT4X4 0x4040
+
#define ZINITIX_FIRMWARE_VERSION 0x0012
#define ZINITIX_USB_DETECT 0x116
@@ -62,7 +69,11 @@
#define ZINITIX_Y_RESOLUTION 0x00C1
#define ZINITIX_POINT_STATUS_REG 0x0080
-#define ZINITIX_ICON_STATUS_REG 0x00AA
+
+#define ZINITIX_BT4X2_ICON_STATUS_REG 0x009A
+#define ZINITIX_BT4X3_ICON_STATUS_REG 0x00A0
+#define ZINITIX_BT4X4_ICON_STATUS_REG 0x00A0
+#define ZINITIX_BT5XX_ICON_STATUS_REG 0x00AA
#define ZINITIX_POINT_COORD_REG (ZINITIX_POINT_STATUS_REG + 2)
@@ -119,6 +130,7 @@
#define DEFAULT_TOUCH_POINT_MODE 2
#define MAX_SUPPORTED_FINGER_NUM 5
+#define MAX_SUPPORTED_BUTTON_NUM 8
#define CHIP_ON_DELAY 15 // ms
#define FIRMWARE_ON_DELAY 40 // ms
@@ -146,6 +158,13 @@ struct bt541_ts_data {
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
u32 zinitix_mode;
+ u32 keycodes[MAX_SUPPORTED_BUTTON_NUM];
+ int num_keycodes;
+ bool have_versioninfo;
+ u16 chip_revision;
+ u16 firmware_version;
+ u16 regdata_version;
+ u16 icon_status_reg;
};
static int zinitix_read_data(struct i2c_client *client,
@@ -190,11 +209,25 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
return 0;
}
+static u16 zinitix_get_u16_reg(struct bt541_ts_data *bt541, u16 vreg)
+{
+ struct i2c_client *client = bt541->client;
+ int error;
+ __le16 val;
+
+ error = zinitix_read_data(client, vreg, (void *)&val, 2);
+ if (error)
+ return U8_MAX;
+
+ return le16_to_cpu(val);
+}
+
static int zinitix_init_touch(struct bt541_ts_data *bt541)
{
struct i2c_client *client = bt541->client;
int i;
int error;
+ u16 int_flags;
error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
if (error) {
@@ -202,6 +235,47 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
return error;
}
+ /*
+ * Read and cache the chip revision and firmware version the first time
+ * we get here.
+ */
+ if (!bt541->have_versioninfo) {
+ bt541->chip_revision = zinitix_get_u16_reg(bt541,
+ ZINITIX_CHIP_REVISION);
+ bt541->firmware_version = zinitix_get_u16_reg(bt541,
+ ZINITIX_FIRMWARE_VERSION);
+ bt541->regdata_version = zinitix_get_u16_reg(bt541,
+ ZINITIX_DATA_VERSION_REG);
+ bt541->have_versioninfo = true;
+
+ dev_dbg(&client->dev,
+ "chip revision %04x firmware version %04x regdata version %04x\n",
+ bt541->chip_revision, bt541->firmware_version,
+ bt541->regdata_version);
+
+ /*
+ * Determine the "icon" status register which varies by the
+ * chip.
+ */
+ switch (bt541->chip_revision & ZINITIX_CHIP_BTX0X_MASK) {
+ case ZINITIX_CHIP_BT4X2:
+ bt541->icon_status_reg = ZINITIX_BT4X2_ICON_STATUS_REG;
+ break;
+
+ case ZINITIX_CHIP_BT4X3:
+ bt541->icon_status_reg = ZINITIX_BT4X3_ICON_STATUS_REG;
+ break;
+
+ case ZINITIX_CHIP_BT4X4:
+ bt541->icon_status_reg = ZINITIX_BT4X4_ICON_STATUS_REG;
+ break;
+
+ default:
+ bt541->icon_status_reg = ZINITIX_BT5XX_ICON_STATUS_REG;
+ break;
+ }
+ }
+
error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
if (error) {
dev_err(&client->dev,
@@ -225,6 +299,11 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
if (error)
return error;
+ error = zinitix_write_u16(client, ZINITIX_BUTTON_SUPPORTED_NUM,
+ bt541->num_keycodes);
+ if (error)
+ return error;
+
error = zinitix_write_u16(client, ZINITIX_INITIAL_TOUCH_MODE,
bt541->zinitix_mode);
if (error)
@@ -235,9 +314,11 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
if (error)
return error;
- error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG,
- BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
- BIT_UP);
+ int_flags = BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE | BIT_UP;
+ if (bt541->num_keycodes)
+ int_flags |= BIT_ICON_EVENT;
+
+ error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, int_flags);
if (error)
return error;
@@ -260,7 +341,7 @@ static int zinitix_init_regulators(struct bt541_ts_data *bt541)
* so check if "vddo" is present and in that case use these names.
* Else use the proper supply names on the component.
*/
- if (of_find_property(dev->of_node, "vddo-supply", NULL)) {
+ if (of_property_present(dev->of_node, "vddo-supply")) {
bt541->supplies[0].supply = "vdd";
bt541->supplies[1].supply = "vddo";
} else {
@@ -350,12 +431,22 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
}
}
+static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
+{
+ int i;
+
+ for (i = 0; i < bt541->num_keycodes; i++)
+ input_report_key(bt541->input_dev,
+ bt541->keycodes[i], icon_events & BIT(i));
+}
+
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
{
struct bt541_ts_data *bt541 = bt541_handler;
struct i2c_client *client = bt541->client;
struct touch_event touch_event;
unsigned long finger_mask;
+ __le16 icon_events;
int error;
int i;
@@ -368,6 +459,17 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
goto out;
}
+ if (le16_to_cpu(touch_event.status) & BIT_ICON_EVENT) {
+ error = zinitix_read_data(bt541->client, bt541->icon_status_reg,
+ &icon_events, sizeof(icon_events));
+ if (error) {
+ dev_err(&client->dev, "Failed to read icon events\n");
+ goto out;
+ }
+
+ zinitix_report_keys(bt541, le16_to_cpu(icon_events));
+ }
+
finger_mask = touch_event.finger_mask;
for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
const struct point_coord *p = &touch_event.point_coord[i];
@@ -453,6 +555,7 @@ static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
{
struct input_dev *input_dev;
int error;
+ int i;
input_dev = devm_input_allocate_device(&bt541->client->dev);
if (!input_dev) {
@@ -470,6 +573,14 @@ static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
input_dev->open = zinitix_input_open;
input_dev->close = zinitix_input_close;
+ if (bt541->num_keycodes) {
+ input_dev->keycode = bt541->keycodes;
+ input_dev->keycodemax = bt541->num_keycodes;
+ input_dev->keycodesize = sizeof(bt541->keycodes[0]);
+ for (i = 0; i < bt541->num_keycodes; i++)
+ input_set_capability(input_dev, EV_KEY, bt541->keycodes[i]);
+ }
+
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
@@ -534,6 +645,31 @@ static int zinitix_ts_probe(struct i2c_client *client)
return error;
}
+ if (device_property_present(&client->dev, "linux,keycodes")) {
+ bt541->num_keycodes = device_property_count_u32(&client->dev,
+ "linux,keycodes");
+ if (bt541->num_keycodes < 0) {
+ dev_err(&client->dev, "Failed to count keys (%d)\n",
+ bt541->num_keycodes);
+ return bt541->num_keycodes;
+ } else if (bt541->num_keycodes > ARRAY_SIZE(bt541->keycodes)) {
+ dev_err(&client->dev, "Too many keys defined (%d)\n",
+ bt541->num_keycodes);
+ return -EINVAL;
+ }
+
+ error = device_property_read_u32_array(&client->dev,
+ "linux,keycodes",
+ bt541->keycodes,
+ bt541->num_keycodes);
+ if (error) {
+ dev_err(&client->dev,
+ "Unable to parse \"linux,keycodes\" property: %d\n",
+ error);
+ return error;
+ }
+ }
+
error = zinitix_init_input_dev(bt541);
if (error) {
dev_err(&client->dev,
@@ -562,7 +698,7 @@ static int zinitix_ts_probe(struct i2c_client *client)
return 0;
}
-static int __maybe_unused zinitix_suspend(struct device *dev)
+static int zinitix_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
@@ -577,7 +713,7 @@ static int __maybe_unused zinitix_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused zinitix_resume(struct device *dev)
+static int zinitix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
@@ -593,7 +729,7 @@ static int __maybe_unused zinitix_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
#ifdef CONFIG_OF
static const struct of_device_id zinitix_of_match[] = {
@@ -617,10 +753,10 @@ MODULE_DEVICE_TABLE(of, zinitix_of_match);
#endif
static struct i2c_driver zinitix_ts_driver = {
- .probe_new = zinitix_ts_probe,
+ .probe = zinitix_ts_probe,
.driver = {
.name = "Zinitix-TS",
- .pm = &zinitix_pm_ops,
+ .pm = pm_sleep_ptr(&zinitix_pm_ops),
.of_match_table = of_match_ptr(zinitix_of_match),
},
};
diff --git a/drivers/input/touchscreen/zylonite-wm97xx.c b/drivers/input/touchscreen/zylonite-wm97xx.c
deleted file mode 100644
index a70fe4abe520..000000000000
--- a/drivers/input/touchscreen/zylonite-wm97xx.c
+++ /dev/null
@@ -1,220 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * zylonite-wm97xx.c -- Zylonite Continuous Touch screen driver
- *
- * Copyright 2004, 2007, 2008 Wolfson Microelectronics PLC.
- * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
- * Parts Copyright : Ian Molton <spyro@f2s.com>
- * Andrew Zabolotny <zap@homelink.ru>
- *
- * Notes:
- * This is a wm97xx extended touch driver supporting interrupt driven
- * and continuous operation on Marvell Zylonite development systems
- * (which have a WM9713 on board).
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/soc/pxa/cpu.h>
-#include <linux/wm97xx.h>
-
-#include <sound/pxa2xx-lib.h>
-
-struct continuous {
- u16 id; /* codec id */
- u8 code; /* continuous code */
- u8 reads; /* number of coord reads per read cycle */
- u32 speed; /* number of coords per second */
-};
-
-#define WM_READS(sp) ((sp / HZ) + 1)
-
-static const struct continuous cinfo[] = {
- { WM9713_ID2, 0, WM_READS(94), 94 },
- { WM9713_ID2, 1, WM_READS(120), 120 },
- { WM9713_ID2, 2, WM_READS(154), 154 },
- { WM9713_ID2, 3, WM_READS(188), 188 },
-};
-
-/* continuous speed index */
-static int sp_idx;
-
-/*
- * Pen sampling frequency (Hz) in continuous mode.
- */
-static int cont_rate = 200;
-module_param(cont_rate, int, 0);
-MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
-
-/*
- * Pressure readback.
- *
- * Set to 1 to read back pen down pressure
- */
-static int pressure;
-module_param(pressure, int, 0);
-MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
-
-/*
- * AC97 touch data slot.
- *
- * Touch screen readback data ac97 slot
- */
-static int ac97_touch_slot = 5;
-module_param(ac97_touch_slot, int, 0);
-MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
-
-
-/* flush AC97 slot 5 FIFO machines */
-static void wm97xx_acc_pen_up(struct wm97xx *wm)
-{
- int i;
-
- msleep(1);
-
- for (i = 0; i < 16; i++)
- pxa2xx_ac97_read_modr();
-}
-
-static int wm97xx_acc_pen_down(struct wm97xx *wm)
-{
- u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
- int reads = 0;
- static u16 last, tries;
-
- /* When the AC97 queue has been drained we need to allow time
- * to buffer up samples otherwise we end up spinning polling
- * for samples. The controller can't have a suitably low
- * threshold set to use the notifications it gives.
- */
- msleep(1);
-
- if (tries > 5) {
- tries = 0;
- return RC_PENUP;
- }
-
- x = pxa2xx_ac97_read_modr();
- if (x == last) {
- tries++;
- return RC_AGAIN;
- }
- last = x;
- do {
- if (reads)
- x = pxa2xx_ac97_read_modr();
- y = pxa2xx_ac97_read_modr();
- if (pressure)
- p = pxa2xx_ac97_read_modr();
-
- dev_dbg(wm->dev, "Raw coordinates: x=%x, y=%x, p=%x\n",
- x, y, p);
-
- /* are samples valid */
- if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X ||
- (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y ||
- (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES)
- goto up;
-
- /* coordinate is good */
- tries = 0;
- input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
- input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
- input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
- input_report_key(wm->input_dev, BTN_TOUCH, (p != 0));
- input_sync(wm->input_dev);
- reads++;
- } while (reads < cinfo[sp_idx].reads);
-up:
- return RC_PENDOWN | RC_AGAIN;
-}
-
-static int wm97xx_acc_startup(struct wm97xx *wm)
-{
- int idx;
-
- /* check we have a codec */
- if (wm->ac97 == NULL)
- return -ENODEV;
-
- /* Go you big red fire engine */
- for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
- if (wm->id != cinfo[idx].id)
- continue;
- sp_idx = idx;
- if (cont_rate <= cinfo[idx].speed)
- break;
- }
- wm->acc_rate = cinfo[sp_idx].code;
- wm->acc_slot = ac97_touch_slot;
- dev_info(wm->dev,
- "zylonite accelerated touchscreen driver, %d samples/sec\n",
- cinfo[sp_idx].speed);
-
- return 0;
-}
-
-static struct wm97xx_mach_ops zylonite_mach_ops = {
- .acc_enabled = 1,
- .acc_pen_up = wm97xx_acc_pen_up,
- .acc_pen_down = wm97xx_acc_pen_down,
- .acc_startup = wm97xx_acc_startup,
- .irq_gpio = WM97XX_GPIO_2,
-};
-
-static int zylonite_wm97xx_probe(struct platform_device *pdev)
-{
- struct wm97xx *wm = platform_get_drvdata(pdev);
- struct gpio_desc *gpio_touch_irq;
- int err;
-
- gpio_touch_irq = devm_gpiod_get(&pdev->dev, "touch", GPIOD_IN);
- err = PTR_ERR_OR_ZERO(gpio_touch_irq);
- if (err) {
- dev_err(&pdev->dev, "Cannot get irq gpio: %d\n", err);
- return err;
- }
-
- wm->pen_irq = gpiod_to_irq(gpio_touch_irq);
- irq_set_irq_type(wm->pen_irq, IRQ_TYPE_EDGE_BOTH);
-
- wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
- WM97XX_GPIO_POL_HIGH,
- WM97XX_GPIO_STICKY,
- WM97XX_GPIO_WAKE);
- wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
- WM97XX_GPIO_POL_HIGH,
- WM97XX_GPIO_NOTSTICKY,
- WM97XX_GPIO_NOWAKE);
-
- return wm97xx_register_mach_ops(wm, &zylonite_mach_ops);
-}
-
-static int zylonite_wm97xx_remove(struct platform_device *pdev)
-{
- struct wm97xx *wm = platform_get_drvdata(pdev);
-
- wm97xx_unregister_mach_ops(wm);
-
- return 0;
-}
-
-static struct platform_driver zylonite_wm97xx_driver = {
- .probe = zylonite_wm97xx_probe,
- .remove = zylonite_wm97xx_remove,
- .driver = {
- .name = "wm97xx-touch",
- },
-};
-module_platform_driver(zylonite_wm97xx_driver);
-
-/* Module information */
-MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
-MODULE_DESCRIPTION("wm97xx continuous touch driver for Zylonite");
-MODULE_LICENSE("GPL");