提交 10fdfee7 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 "The most notable item is addition of support for Synaptics RMI4
  protocol which is native protocol for all current Synaptics devices
  (touchscreens, touchpads).  In later releases we'll switch devices
  using HID and PS/2 protocol emulation to RMI4.

  You will also get:
   - BYD PS/2 touchpad protocol support for psmouse
   - MELFAS MIP4 Touchscreen driver
   - rotary encoder was moved away from legacy platform data and to
     generic device properties API, devm_* API, and can now handle
     encoders using more than 2 GPIOs
   - Cypress touchpad driver was switched to devm_* API and device
     properties
   - other assorted driver fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (40 commits)
  ARM: pxa/raumfeld: use PROPERTY_ENTRY_INTEGER to define props
  Input: synaptics-rmi4 - using logical instead of bitwise AND
  Input: powermate - fix oops with malicious USB descriptors
  Input: snvs_pwrkey - fix returned value check of syscon_regmap_lookup_by_phandle()
  MAINTAINERS: add devicetree bindings to Input Drivers section
  Input: synaptics-rmi4 - add device tree support to the SPI transport driver
  Input: synaptics-rmi4 - add SPI transport driver
  Input: synaptics-rmi4 - add support for F30
  Input: synaptics-rmi4 - add support for F12
  Input: synaptics-rmi4 - add device tree support for 2d sensors and F11
  Input: synaptics-rmi4 - add support for 2D sensors and F11
  Input: synaptics-rmi4 - add device tree support for RMI4 I2C devices
  Input: synaptics-rmi4 - add I2C transport driver
  Input: synaptics-rmi4 - add support for Synaptics RMI4 devices
  Input: ad7879 - add device tree support
  Input: ad7879 - fix default x/y axis assignment
  Input: ad7879 - move header to platform_data directory
  Input: ts4800 - add hardware dependency
  Input: cyapa - fix for losing events during device power transitions
  Input: sh_keysc - remove dependency on SUPERH
  ...
Android Goldfish Events Keypad
Android goldfish events keypad device generated by android emulator.
Required properties:
- compatible : should contain "google,goldfish-events-keypad" to match emulator
- reg : <registers mapping>
- interrupts : <interrupt mapping>
Example:
goldfish-events@9040000 {
compatible = "google,goldfish-events-keypad";
reg = <0x9040000 0x1000>;
interrupts = <0x5>;
};
Synaptics RMI4 2D Sensor Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices which contain 2D sensors using Function 11 or
Function 12. Complete documentation for transports and other functions
can be found in:
Documentation/devicetree/bindings/input/rmi4.
RMI4 Function 11 and Function 12 are for 2D touch position sensing.
Additional documentation for F11 can be found at:
http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
Optional Touch Properties:
Description in Documentation/devicetree/bindings/input/touch
- touchscreen-inverted-x
- touchscreen-inverted-y
- touchscreen-swapped-x-y
- touchscreen-x-mm
- touchscreen-y-mm
Optional Properties:
- syna,clip-x-low: Sets a minimum value for X.
- syna,clip-y-low: Sets a minimum value for Y.
- syna,clip-x-high: Sets a maximum value for X.
- syna,clip-y-high: Sets a maximum value for Y.
- syna,offset-x: Add an offset to X.
- syna,offset-y: Add an offset to Y.
- syna,delta-x-threshold: Set the minimum distance on the X axis required
to generate an interrupt in reduced reporting
mode.
- syna,delta-y-threshold: Set the minimum distance on the Y axis required
to generate an interrupt in reduced reporting
mode.
- syna,sensor-type: Set the sensor type. 1 for touchscreen 2 for touchpad.
- syna,disable-report-mask: Mask for disabling posiiton reporting. Used to
disable reporing absolute position data.
- syna,rezero-wait-ms: Time in miliseconds to wait after issuing a rezero
command.
Example of a RMI4 I2C device with F11:
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
...
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};
Synaptics RMI4 F01 Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices which contain Function 1. Complete documentation
for transports and other functions can be found in:
Documentation/devicetree/bindings/input/rmi4.
Additional documentation for F01 can be found at:
http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
Optional Properties:
- syna,nosleep-mode: If set the device will run at full power without sleeping.
nosleep has 3 modes, 0 will not change the default
setting, 1 will disable nosleep (allow sleeping),
and 2 will enable nosleep (disabling sleep).
- syna,wakeup-threshold: Defines the amplitude of the disturbance to the
background capacitance that will cause the
device to wake from dozing.
- syna,doze-holdoff-ms: The delay to wait after the last finger lift and the
first doze cycle.
- syna,doze-interval-ms: The time period that the device sleeps between finger
activity.
Example of a RMI4 I2C device with F01:
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
...
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
};
};
Synaptics RMI4 I2C Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices using the I2C transport driver. Complete documentation
for other transports and functions can be found in
Documentation/devicetree/bindings/input/rmi4.
Required Properties:
- compatible: syna,rmi4-i2c
- reg: I2C address
- #address-cells: Set to 1 to indicate that the function child nodes
consist of only on uint32 value.
- #size-cells: Set to 0 to indicate that the function child nodes do not
have a size property.
Optional Properties:
- interrupts: interrupt which the rmi device is connected to.
- interrupt-parent: The interrupt controller.
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- syna,reset-delay-ms: The number of milliseconds to wait after resetting the
device.
Function Parameters:
Parameters specific to RMI functions are contained in child nodes of the rmi device
node. Documentation for the parameters of each function can be found in:
Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt.
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
reg = <0x2c>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&gpio>;
interrupts = <4 2>;
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};
Synaptics RMI4 SPI Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices using the SPI transport driver. Complete documentation
for other transports and functions can be found in
Documentation/devicetree/bindings/input/rmi4.
Required Properties:
- compatible: syna,rmi4-spi
- reg: Chip select address for the device
- #address-cells: Set to 1 to indicate that the function child nodes
consist of only on uint32 value.
- #size-cells: Set to 0 to indicate that the function child nodes do not
have a size property.
Optional Properties:
- interrupts: interrupt which the rmi device is connected to.
- interrupt-parent: The interrupt controller.
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- spi-rx-delay-us: microsecond delay after a read transfer.
- spi-tx-delay-us: microsecond delay after a write transfer.
Function Parameters:
Parameters specific to RMI functions are contained in child nodes of the rmi device
node. Documentation for the parameters of each function can be found in:
Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt.
Example:
spi@7000d800 {
rmi4-spi-dev@0 {
compatible = "syna,rmi4-spi";
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <4000000>;
spi-cpha;
spi-cpol;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(K, 2) 0x2>;
spi-rx-delay-us = <30>;
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};
Rotary encoder DT bindings
Required properties:
- gpios: a spec for two GPIOs to be used
- gpios: a spec for at least two GPIOs to be used, most significant first
Optional properties:
- linux,axis: the input subsystem axis to map to this rotary encoder.
......
* Analog Devices AD7879(-1)/AD7889(-1) touchscreen interface (SPI/I2C)
Required properties:
- compatible : for SPI slave, use "adi,ad7879"
for I2C slave, use "adi,ad7879-1"
- reg : SPI chipselect/I2C slave address
See spi-bus.txt for more SPI slave properties
- interrupt-parent : the phandle for the interrupt controller
- interrupts : touch controller interrupt
- touchscreen-max-pressure : maximum reported pressure
- adi,resistance-plate-x : total resistance of X-plate (for pressure
calculation)
Optional properties:
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
- adi,first-conversion-delay : 0-12: In 128us steps (starting with 128us)
13 : 2.560ms
14 : 3.584ms
15 : 4.096ms
This property has to be a '/bits/ 8' value
- adi,acquisition-time : 0: 2us
1: 4us
2: 8us
3: 16us
This property has to be a '/bits/ 8' value
- adi,median-filter-size : 0: disabled
1: 4 measurements
2: 8 measurements
3: 16 measurements
This property has to be a '/bits/ 8' value
- adi,averaging : 0: 2 middle values (1 if median disabled)
1: 4 middle values
2: 8 middle values
3: 16 values
This property has to be a '/bits/ 8' value
- adi,conversion-interval: : 0 : convert one time only
1-255: 515us + val * 35us (up to 9.440ms)
This property has to be a '/bits/ 8' value
Example:
ad7879@2c {
compatible = "adi,ad7879-1";
reg = <0x2c>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
touchscreen-max-pressure = <4096>;
adi,resistance-plate-x = <120>;
adi,first-conversion-delay = /bits/ 8 <3>;
adi,acquisition-time = /bits/ 8 <1>;
adi,median-filter-size = /bits/ 8 <2>;
adi,averaging = /bits/ 8 <1>;
adi,conversion-interval = /bits/ 8 <255>;
};
* Cypress cyttsp touchscreen controller
Required properties:
- compatible : must be "cypress,cyttsp-i2c" or "cypress,cyttsp-spi"
- reg : Device I2C address or SPI chip select number
- spi-max-frequency : Maximum SPI clocking speed of the device (for cyttsp-spi)
- interrupt-parent : the phandle for the gpio controller
(see interrupt binding[0]).
- interrupts : (gpio) interrupt to which the chip is connected
(see interrupt binding[0]).
- bootloader-key : the 8-byte bootloader key that is required to switch
the chip from bootloader mode (default mode) to
application mode.
This property has to be specified as an array of 8
'/bits/ 8' values.
Optional properties:
- reset-gpios : the reset gpio the chip is connected to
(see GPIO binding[1] for more details).
- touchscreen-size-x : horizontal resolution of touchscreen (in pixels)
- touchscreen-size-y : vertical resolution of touchscreen (in pixels)
- touchscreen-fuzz-x : horizontal noise value of the absolute input device
(in pixels)
- touchscreen-fuzz-y : vertical noise value of the absolute input device
(in pixels)
- active-distance : the distance in pixels beyond which a touch must move
before movement is detected and reported by the device.
Valid values: 0-15.
- active-interval-ms : the minimum period in ms between consecutive
scanning/processing cycles when the chip is in active mode.
Valid values: 0-255.
- lowpower-interval-ms : the minimum period in ms between consecutive
scanning/processing cycles when the chip is in low-power mode.
Valid values: 0-2550
- touch-timeout-ms : minimum time in ms spent in the active power state while no
touches are detected before entering low-power mode.
Valid values: 0-2550
- use-handshake : enable register-based handshake (boolean). This should
only be used if the chip is configured to use 'blocking
communication with timeout' (in this case the device
generates an interrupt at the end of every
scanning/processing cycle).
[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
[1]: Documentation/devicetree/bindings/gpio/gpio.txt
Example:
&i2c1 {
/* ... */
cyttsp@a {
compatible = "cypress,cyttsp-i2c";
reg = <0xa>;
interrupt-parent = <&gpio0>;
interrupts = <28 0>;
reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
touchscreen-fuzz-x = <4>;
touchscreen-fuzz-y = <7>;
bootloader-key = /bits/ 8 <0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08>;
active-distance = <8>;
active-interval-ms = <0>;
lowpower-interval-ms = <200>;
touch-timeout-ms = <100>;
};
/* ... */
};
&mcspi1 {
/* ... */
cyttsp@0 {
compatible = "cypress,cyttsp-spi";
spi-max-frequency = <6000000>;
reg = <0>;
interrupt-parent = <&gpio0>;
interrupts = <28 0>;
reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
touchscreen-fuzz-x = <4>;
touchscreen-fuzz-y = <7>;
bootloader-key = /bits/ 8 <0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08>;
active-distance = <8>;
active-interval-ms = <0>;
lowpower-interval-ms = <200>;
touch-timeout-ms = <100>;
};
/* ... */
};
......@@ -18,6 +18,8 @@ Optional properties for Touchscreens:
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
Swapping is done after inverting the axis
- touchscreen-x-mm : horizontal length in mm of the touchscreen
- touchscreen-y-mm : vertical length in mm of the touchscreen
Deprecated properties for Touchscreens:
- x-size : deprecated name for touchscreen-size-x
......
......@@ -61,6 +61,8 @@ contain the following properties.
used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width(number of data wires) that
used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD).
......
......@@ -229,6 +229,7 @@ st STMicroelectronics
startek Startek
ste ST-Ericsson
stericsson ST-Ericsson
syna Synaptics Inc.
synology Synology, Inc.
SUNW Sun Microsystems, Inc
tbs TBS Technologies
......
......@@ -5581,6 +5581,7 @@ F: drivers/input/
F: include/linux/input.h
F: include/uapi/linux/input.h
F: include/linux/input/
F: Documentation/devicetree/bindings/input/
INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@bitmath.org>
......
......@@ -18,12 +18,13 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/property.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/smsc911x.h>
#include <linux/input.h>
#include <linux/rotary_encoder.h>
#include <linux/gpio_keys.h>
#include <linux/input/eeti_ts.h>
#include <linux/leds.h>
......@@ -366,22 +367,31 @@ static struct pxaohci_platform_data raumfeld_ohci_info = {
* Rotary encoder input device
*/
static struct rotary_encoder_platform_data raumfeld_rotary_encoder_info = {
.steps = 24,
.axis = REL_X,
.relative_axis = 1,
.gpio_a = GPIO_VOLENC_A,
.gpio_b = GPIO_VOLENC_B,
.inverted_a = 1,
.inverted_b = 0,
static struct gpiod_lookup_table raumfeld_rotary_gpios_table = {
.dev_id = "rotary-encoder.0",
.table = {
GPIO_LOOKUP_IDX("gpio-0",
GPIO_VOLENC_A, NULL, 0, GPIO_ACTIVE_LOW),
GPIO_LOOKUP_IDX("gpio-0",
GPIO_VOLENC_B, NULL, 1, GPIO_ACTIVE_HIGH),
{ },
},
};
static struct property_entry raumfeld_rotary_properties[] = {
PROPERTY_ENTRY_INTEGER("rotary-encoder,steps-per-period", u32, 24),
PROPERTY_ENTRY_INTEGER("linux,axis", u32, REL_X),
PROPERTY_ENTRY_INTEGER("rotary-encoder,relative_axis", u32, 1),
{ },
};
static struct property_set raumfeld_rotary_property_set = {
.properties = raumfeld_rotary_properties,
};
static struct platform_device rotary_encoder_device = {
.name = "rotary-encoder",
.id = 0,
.dev = {
.platform_data = &raumfeld_rotary_encoder_info,
}
};
/**
......@@ -1051,7 +1061,12 @@ static void __init __maybe_unused raumfeld_controller_init(void)
int ret;
pxa3xx_mfp_config(ARRAY_AND_SIZE(raumfeld_controller_pin_config));
gpiod_add_lookup_table(&raumfeld_rotary_gpios_table);
device_add_property_set(&rotary_encoder_device.dev,
&raumfeld_rotary_property_set);
platform_device_register(&rotary_encoder_device);
spi_register_board_info(ARRAY_AND_SIZE(controller_spi_devices));
i2c_register_board_info(0, &raumfeld_controller_i2c_board_info, 1);
......@@ -1086,6 +1101,10 @@ static void __init __maybe_unused raumfeld_speaker_init(void)
i2c_register_board_info(0, &raumfeld_connector_i2c_board_info, 1);
platform_device_register(&smc91x_device);
gpiod_add_lookup_table(&raumfeld_rotary_gpios_table);
device_add_property_set(&rotary_encoder_device.dev,
&raumfeld_rotary_property_set);
platform_device_register(&rotary_encoder_device);
raumfeld_audio_init();
......
......@@ -279,7 +279,7 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_AD7879)
#include <linux/spi/ad7879.h>
#include <linux/platform_data/ad7879.h>
static const struct ad7879_platform_data bfin_ad7879_ts_info = {
.model = 7879, /* Model = AD7879 */
.x_plate_ohms = 620, /* 620 Ohm from the touch datasheet */
......
......@@ -477,7 +477,7 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_AD7879)
#include <linux/spi/ad7879.h>
#include <linux/platform_data/ad7879.h>
static const struct ad7879_platform_data bfin_ad7879_ts_info = {
.model = 7879, /* Model = AD7879 */
.x_plate_ohms = 620, /* 620 Ohm from the touch datasheet */
......
......@@ -29,7 +29,7 @@
#include <asm/dpmc.h>
#if IS_ENABLED(CONFIG_TOUCHSCREEN_AD7879)
#include <linux/spi/ad7879.h>
#include <linux/platform_data/ad7879.h>
#define LCD_BACKLIGHT_GPIO 0x40
/* TLL6527M uses TLL7UIQ35 / ADI LCD EZ Extender. AD7879 AUX GPIO is used for
* LCD Backlight Enable
......
......@@ -776,7 +776,7 @@ static const struct ad7877_platform_data bfin_ad7877_ts_info = {
#endif
#if IS_ENABLED(CONFIG_TOUCHSCREEN_AD7879)
#include <linux/spi/ad7879.h>
#include <linux/platform_data/ad7879.h>
static const struct ad7879_platform_data bfin_ad7879_ts_info = {
.model = 7879, /* Model = AD7879 */
.x_plate_ohms = 620, /* 620 Ohm from the touch datasheet */
......
......@@ -521,7 +521,7 @@ static struct bfin5xx_spi_chip spi_flash_chip_info = {
#endif /* CONFIG_SPI_BFIN5XX */
#if IS_ENABLED(CONFIG_TOUCHSCREEN_AD7879)
#include <linux/spi/ad7879.h>
#include <linux/platform_data/ad7879.h>
static const struct ad7879_platform_data bfin_ad7879_ts_info = {
.model = 7879, /* Model = AD7879 */
.x_plate_ohms = 620, /* 620 Ohm from the touch datasheet */
......
......@@ -201,6 +201,8 @@ source "drivers/input/touchscreen/Kconfig"
source "drivers/input/misc/Kconfig"
source "drivers/input/rmi4/Kconfig"
endif
menu "Hardware I/O ports"
......
......@@ -26,3 +26,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_RMI4_CORE) += rmi4/
......@@ -560,7 +560,7 @@ config KEYBOARD_SUNKBD
config KEYBOARD_SH_KEYSC
tristate "SuperH KEYSC keypad support"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
depends on ARCH_SHMOBILE || COMPILE_TEST
help
Say Y here if you want to use a keypad attached to the KEYSC block
on SuperH processors such as sh7722 and sh7343.
......
......@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/acpi.h>
enum {
REG_READ = 0x00,
......@@ -178,10 +179,26 @@ static int events_probe(struct platform_device *pdev)
return 0;
}
static const struct of_device_id goldfish_events_of_match[] = {
{ .compatible = "google,goldfish-events-keypad", },
{},
};
MODULE_DEVICE_TABLE(of, goldfish_events_of_match);
#ifdef CONFIG_ACPI
static const struct acpi_device_id goldfish_events_acpi_match[] = {
{ "GFSH0002", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, goldfish_events_acpi_match);
#endif
static struct platform_driver events_driver = {
.probe = events_probe,
.driver = {
.name = "goldfish_events",
.of_match_table = goldfish_events_of_match,
.acpi_match_table = ACPI_PTR(goldfish_events_acpi_match),
},
};
......
......@@ -111,9 +111,9 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
return -ENOMEM;
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");
if (!pdata->snvs) {
if (IS_ERR(pdata->snvs)) {
dev_err(&pdev->dev, "Can't get snvs syscon\n");
return -ENODEV;
return PTR_ERR(pdata->snvs);
}
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
......@@ -180,7 +180,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
return 0;
}
static int imx_snvs_pwrkey_suspend(struct device *dev)
static int __maybe_unused imx_snvs_pwrkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
......@@ -191,7 +191,7 @@ static int imx_snvs_pwrkey_suspend(struct device *dev)
return 0;
}
static int imx_snvs_pwrkey_resume(struct device *dev)
static int __maybe_unused imx_snvs_pwrkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
......
......@@ -288,8 +288,7 @@ static int spear_kbd_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int spear_kbd_suspend(struct device *dev)
static int __maybe_unused spear_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct spear_kbd *kbd = platform_get_drvdata(pdev);
......@@ -342,7 +341,7 @@ static int spear_kbd_suspend(struct device *dev)
return 0;
}
static int spear_kbd_resume(struct device *dev)
static int __maybe_unused spear_kbd_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct spear_kbd *kbd = platform_get_drvdata(pdev);
......@@ -368,7 +367,6 @@ static int spear_kbd_resume(struct device *dev)
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
......
......@@ -307,6 +307,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
int error = -ENOMEM;
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints < 1)
return -EINVAL;
endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -EIO;
......
......@@ -20,70 +20,78 @@
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/rotary_encoder.h>
#include <linux/gpio/consumer.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/property.h>
#define DRV_NAME "rotary-encoder"
struct rotary_encoder {
struct input_dev *input;
const struct rotary_encoder_platform_data *pdata;
unsigned int axis;
struct mutex access_mutex;
u32 steps;
u32 axis;
bool relative_axis;
bool rollover;
unsigned int pos;
unsigned int irq_a;
unsigned int irq_b;
struct gpio_descs *gpios;
unsigned int *irq;
bool armed;
unsigned char dir; /* 0 - clockwise, 1 - CCW */
signed char dir; /* 1 - clockwise, -1 - CCW */
char last_stable;
unsigned last_stable;
};
static int rotary_encoder_get_state(const struct rotary_encoder_platform_data *pdata)
static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder)
{
int a = !!gpio_get_value(pdata->gpio_a);
int b = !!gpio_get_value(pdata->gpio_b);
int i;
unsigned ret = 0;
a ^= pdata->inverted_a;
b ^= pdata->inverted_b;
for (i = 0; i < encoder->gpios->ndescs; ++i) {
int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]);
/* convert from gray encoding to normal */
if (ret & 1)
val = !val;
return ((a << 1) | b);
ret = ret << 1 | val;
}
return ret & 3;
}
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
{
const struct rotary_encoder_platform_data *pdata = encoder->pdata;
if (pdata->relative_axis) {
if (encoder->relative_axis) {
input_report_rel(encoder->input,
pdata->axis, encoder->dir ? -1 : 1);
encoder->axis, encoder->dir);
} else {
unsigned int pos = encoder->pos;
if (encoder->dir) {
if (encoder->dir < 0) {
/* turning counter-clockwise */
if (pdata->rollover)
pos += pdata->steps;
if (encoder->rollover)
pos += encoder->steps;
if (pos)
pos--;
} else {
/* turning clockwise */
if (pdata->rollover || pos < pdata->steps)
if (encoder->rollover || pos < encoder->steps)
pos++;
}
if (pdata->rollover)
pos %= pdata->steps;
if (encoder->rollover)
pos %= encoder->steps;
encoder->pos = pos;
input_report_abs(encoder->input, pdata->axis, encoder->pos);
input_report_abs(encoder->input, encoder->axis, encoder->pos);
}
input_sync(encoder->input);
......@@ -92,9 +100,11 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder)
static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
{
struct rotary_encoder *encoder = dev_id;
int state;
unsigned state;
state = rotary_encoder_get_state(encoder->pdata);
mutex_lock(&encoder->access_mutex);
state = rotary_encoder_get_state(encoder);
switch (state) {
case 0x0:
......@@ -105,334 +115,227 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
break;
case 0x1:
case 0x2:
case 0x3:
if (encoder->armed)
encoder->dir = state - 1;
encoder->dir = 2 - state;
break;
case 0x3:
case 0x2:
encoder->armed = true;
break;
}
mutex_unlock(&encoder->access_mutex);
return IRQ_HANDLED;
}
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
{
struct rotary_encoder *encoder = dev_id;
int state;
unsigned int state;
state = rotary_encoder_get_state(encoder->pdata);
mutex_lock(&encoder->access_mutex);
switch (state) {
case 0x00:
case 0x03:
state = rotary_encoder_get_state(encoder);
if (state & 1) {
encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1;
} else {
if (state != encoder->last_stable) {
rotary_encoder_report_event(encoder);
encoder->last_stable = state;
}
break;
case 0x01:
case 0x02:
encoder->dir = (encoder->last_stable + state) & 0x01;
break;
}
mutex_unlock(&encoder->access_mutex);
return IRQ_HANDLED;
}
static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
{
struct rotary_encoder *encoder = dev_id;
unsigned char sum;
int state;
state = rotary_encoder_get_state(encoder->pdata);
/*
* We encode the previous and the current state using a byte.
* The previous state in the MSB nibble, the current state in the LSB
* nibble. Then use a table to decide the direction of the turn.
*/
sum = (encoder->last_stable << 4) + state;
switch (sum) {
case 0x31:
case 0x10:
case 0x02:
case 0x23:
encoder->dir = 0; /* clockwise */
break;
unsigned int state;
case 0x13:
case 0x01:
case 0x20:
case 0x32:
encoder->dir = 1; /* counter-clockwise */
break;
mutex_lock(&encoder->access_mutex);
default:
/*
* Ignore all other values. This covers the case when the
* state didn't change (a spurious interrupt) and the
* cases where the state changed by two steps, making it
* impossible to tell the direction.
*
* In either case, don't report any event and save the
* state for later.
*/
state = rotary_encoder_get_state(encoder);
if ((encoder->last_stable + 1) % 4 == state)
encoder->dir = 1;
else if (encoder->last_stable == (state + 1) % 4)
encoder->dir = -1;
else
goto out;
}
rotary_encoder_report_event(encoder);
out:
encoder->last_stable = state;
mutex_unlock(&encoder->access_mutex);
return IRQ_HANDLED;
}
#ifdef CONFIG_OF
static const struct of_device_id rotary_encoder_of_match[] = {
{ .compatible = "rotary-encoder", },
{ },
};
MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);
static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct device *dev)
static int rotary_encoder_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(rotary_encoder_of_match, dev);
struct device_node *np = dev->of_node;
struct rotary_encoder_platform_data *pdata;
enum of_gpio_flags flags;
int error;
if (!of_id || !np)
return NULL;
pdata = kzalloc(sizeof(struct rotary_encoder_platform_data),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
of_property_read_u32(np, "rotary-encoder,steps", &pdata->steps);
of_property_read_u32(np, "linux,axis", &pdata->axis);
struct device *dev = &pdev->dev;
struct rotary_encoder *encoder;
struct input_dev *input;
irq_handler_t handler;
u32 steps_per_period;
unsigned int i;
int err;
pdata->gpio_a = of_get_gpio_flags(np, 0, &flags);
pdata->inverted_a = flags & OF_GPIO_ACTIVE_LOW;
encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
if (!encoder)
return -ENOMEM;
pdata->gpio_b = of_get_gpio_flags(np, 1, &flags);
pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW;
mutex_init(&encoder->access_mutex);
pdata->relative_axis =
of_property_read_bool(np, "rotary-encoder,relative-axis");
pdata->rollover = of_property_read_bool(np, "rotary-encoder,rollover");
device_property_read_u32(dev, "rotary-encoder,steps", &encoder->steps);
error = of_property_read_u32(np, "rotary-encoder,steps-per-period",
&pdata->steps_per_period);
if (error) {
err = device_property_read_u32(dev, "rotary-encoder,steps-per-period",
&steps_per_period);
if (err) {
/*
* The 'half-period' property has been deprecated, you must use
* 'steps-per-period' and set an appropriate value, but we still
* need to parse it to maintain compatibility.
* The 'half-period' property has been deprecated, you must
* use 'steps-per-period' and set an appropriate value, but
* we still need to parse it to maintain compatibility. If
* neither property is present we fall back to the one step
* per period behavior.
*/
if (of_property_read_bool(np, "rotary-encoder,half-period")) {
pdata->steps_per_period = 2;
} else {
/* Fallback to one step per period behavior */
pdata->steps_per_period = 1;
}
steps_per_period = device_property_read_bool(dev,
"rotary-encoder,half-period") ? 2 : 1;
}
pdata->wakeup_source = of_property_read_bool(np, "wakeup-source");
encoder->rollover =
device_property_read_bool(dev, "rotary-encoder,rollover");
return pdata;
}
#else
static inline struct rotary_encoder_platform_data *
rotary_encoder_parse_dt(struct device *dev)
{
return NULL;
}
#endif
static int rotary_encoder_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct rotary_encoder_platform_data *pdata = dev_get_platdata(dev);
struct rotary_encoder *encoder;
struct input_dev *input;
irq_handler_t handler;
int err;
if (!pdata) {
pdata = rotary_encoder_parse_dt(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
device_property_read_u32(dev, "linux,axis", &encoder->axis);
encoder->relative_axis =
device_property_read_bool(dev, "rotary-encoder,relative-axis");
if (!pdata) {
dev_err(dev, "missing platform data\n");
return -EINVAL;
}
encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
if (IS_ERR(encoder->gpios)) {
dev_err(dev, "unable to get gpios\n");
return PTR_ERR(encoder->gpios);
}
encoder = kzalloc(sizeof(struct rotary_encoder), GFP_KERNEL);
input = input_allocate_device();
if (!encoder || !input) {
err = -ENOMEM;
goto exit_free_mem;
if (encoder->gpios->ndescs < 2) {
dev_err(dev, "not enough gpios found\n");
return -EINVAL;
}
input = devm_input_allocate_device(dev);
if (!input)
return -ENOMEM;
encoder->input = input;
encoder->pdata = pdata;
input->name = pdev->name;
input->id.bustype = BUS_HOST;
input->dev.parent = dev;
if (pdata->relative_axis) {
input->evbit[0] = BIT_MASK(EV_REL);
input->relbit[0] = BIT_MASK(pdata->axis);
} else {
input->evbit[0] = BIT_MASK(EV_ABS);
input_set_abs_params(encoder->input,
pdata->axis, 0, pdata->steps, 0, 1);
}
/* request the GPIOs */
err = gpio_request_one(pdata->gpio_a, GPIOF_IN, dev_name(dev));
if (err) {
dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_a);
goto exit_free_mem;
}
err = gpio_request_one(pdata->gpio_b, GPIOF_IN, dev_name(dev));
if (err) {
dev_err(dev, "unable to request GPIO %d\n", pdata->gpio_b);
goto exit_free_gpio_a;
}
encoder->irq_a = gpio_to_irq(pdata->gpio_a);
encoder->irq_b = gpio_to_irq(pdata->gpio_b);
if (encoder->relative_axis)
input_set_capability(input, EV_REL, encoder->axis);
else
input_set_abs_params(input,
encoder->axis, 0, encoder->steps, 0, 1);
switch (pdata->steps_per_period) {
switch (steps_per_period >> (encoder->gpios->ndescs - 2)) {
case 4:
handler = &rotary_encoder_quarter_period_irq;
encoder->last_stable = rotary_encoder_get_state(pdata);
encoder->last_stable = rotary_encoder_get_state(encoder);
break;
case 2:
handler = &rotary_encoder_half_period_irq;
encoder->last_stable = rotary_encoder_get_state(pdata);
encoder->last_stable = rotary_encoder_get_state(encoder);
break;
case 1:
handler = &rotary_encoder_irq;
break;
default:
dev_err(dev, "'%d' is not a valid steps-per-period value\n",
pdata->steps_per_period);
err = -EINVAL;
goto exit_free_gpio_b;
steps_per_period);
return -EINVAL;
}
err = request_irq(encoder->irq_a, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
goto exit_free_gpio_b;
}
err = request_irq(encoder->irq_b, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
goto exit_free_irq_a;
encoder->irq =
devm_kzalloc(dev,
sizeof(*encoder->irq) * encoder->gpios->ndescs,
GFP_KERNEL);
if (!encoder->irq)
return -ENOMEM;
for (i = 0; i < encoder->gpios->ndescs; ++i) {
encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]);
err = devm_request_threaded_irq(dev, encoder->irq[i],
NULL, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d (gpio#%d)\n",
encoder->irq[i], i);
return err;
}
}
err = input_register_device(input);
if (err) {
dev_err(dev, "failed to register input device\n");
goto exit_free_irq_b;
return err;
}
device_init_wakeup(&pdev->dev, pdata->wakeup_source);
device_init_wakeup(dev,
device_property_read_bool(dev, "wakeup-source"));
platform_set_drvdata(pdev, encoder);
return 0;
exit_free_irq_b:
free_irq(encoder->irq_b, encoder);
exit_free_irq_a:
free_irq(encoder->irq_a, encoder);
exit_free_gpio_b:
gpio_free(pdata->gpio_b);
exit_free_gpio_a:
gpio_free(pdata->gpio_a);
exit_free_mem:
input_free_device(input);
kfree(encoder);
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
return err;
}
static int rotary_encoder_remove(struct platform_device *pdev)
{
struct rotary_encoder *encoder = platform_get_drvdata(pdev);
const struct rotary_encoder_platform_data *pdata = encoder->pdata;
device_init_wakeup(&pdev->dev, false);
free_irq(encoder->irq_a, encoder);
free_irq(encoder->irq_b, encoder);
gpio_free(pdata->gpio_a);
gpio_free(pdata->gpio_b);
input_unregister_device(encoder->input);
kfree(encoder);
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rotary_encoder_suspend(struct device *dev)
static int __maybe_unused rotary_encoder_suspend(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
if (device_may_wakeup(dev)) {
enable_irq_wake(encoder->irq_a);
enable_irq_wake(encoder->irq_b);
for (i = 0; i < encoder->gpios->ndescs; ++i)
enable_irq_wake(encoder->irq[i]);
}
return 0;
}
static int rotary_encoder_resume(struct device *dev)
static int __maybe_unused rotary_encoder_resume(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
if (device_may_wakeup(dev)) {
disable_irq_wake(encoder->irq_a);
disable_irq_wake(encoder->irq_b);
for (i = 0; i < encoder->gpios->ndescs; ++i)
disable_irq_wake(encoder->irq[i]);
}
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
rotary_encoder_suspend, rotary_encoder_resume);
rotary_encoder_suspend, rotary_encoder_resume);
#ifdef CONFIG_OF
static const struct of_device_id rotary_encoder_of_match[] = {
{ .compatible = "rotary-encoder", },
{ },
};
MODULE_DEVICE_TABLE(of, rotary_encoder_of_match);
#endif
static struct platform_driver rotary_encoder_driver = {
.probe = rotary_encoder_probe,
.remove = rotary_encoder_remove,
.driver = {
.name = DRV_NAME,
.pm = &rotary_encoder_pm_ops,
......
......@@ -48,6 +48,16 @@ config MOUSE_PS2_ALPS
If unsure, say Y.
config MOUSE_PS2_BYD
bool "BYD PS/2 mouse protocol extension" if EXPERT
default y
depends on MOUSE_PS2
help
Say Y here if you have a BYD PS/2 touchpad connected to
your system.
If unsure, say Y.
config MOUSE_PS2_LOGIPS2PP
bool "Logitech PS/2++ mouse protocol extension" if EXPERT
default y
......
......@@ -28,6 +28,7 @@ cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o
psmouse-objs := psmouse-base.o synaptics.o focaltech.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o
psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
......
/*
* BYD TouchPad PS/2 mouse driver
*
* Copyright (C) 2015 Chris Diamand <chris@diamand.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/libps2.h>
#include <linux/serio.h>
#include "psmouse.h"
#include "byd.h"
#define PS2_Y_OVERFLOW BIT_MASK(7)
#define PS2_X_OVERFLOW BIT_MASK(6)
#define PS2_Y_SIGN BIT_MASK(5)
#define PS2_X_SIGN BIT_MASK(4)
#define PS2_ALWAYS_1 BIT_MASK(3)
#define PS2_MIDDLE BIT_MASK(2)
#define PS2_RIGHT BIT_MASK(1)
#define PS2_LEFT BIT_MASK(0)
/*
* The touchpad reports gestures in the last byte of each packet. It can take
* any of the following values:
*/
/* One-finger scrolling in one of the edge scroll zones. */
#define BYD_SCROLLUP 0xCA
#define BYD_SCROLLDOWN 0x36
#define BYD_SCROLLLEFT 0xCB
#define BYD_SCROLLRIGHT 0x35
/* Two-finger scrolling. */
#define BYD_2DOWN 0x2B
#define BYD_2UP 0xD5
#define BYD_2LEFT 0xD6
#define BYD_2RIGHT 0x2A
/* Pinching in or out. */
#define BYD_ZOOMOUT 0xD8
#define BYD_ZOOMIN 0x28
/* Three-finger swipe. */
#define BYD_3UP 0xD3
#define BYD_3DOWN 0x2D
#define BYD_3LEFT 0xD4
#define BYD_3RIGHT 0x2C
/* Four-finger swipe. */
#define BYD_4UP 0xCD
#define BYD_4DOWN 0x33
int byd_detect(struct psmouse *psmouse, bool set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
param[0] = 0x03;
param[1] = 0x00;
param[2] = 0x00;
param[3] = 0x00;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
return -1;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
return -1;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
return -1;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
return -1;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
if (param[1] != 0x03 || param[2] != 0x64)
return -ENODEV;
psmouse_dbg(psmouse, "BYD touchpad detected\n");
if (set_properties) {
psmouse->vendor = "BYD";
psmouse->name = "TouchPad";
}
return 0;
}
static psmouse_ret_t byd_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
u8 *pkt = psmouse->packet;
if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) {
psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n",
pkt[0]);
return PSMOUSE_BAD_DATA;
}
if (psmouse->pktcnt < psmouse->pktsize)
return PSMOUSE_GOOD_DATA;
/* Otherwise, a full packet has been received */
switch (pkt[3]) {
case 0: {
/* Standard packet */
/* Sign-extend if a sign bit is set. */
unsigned int signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0;
unsigned int signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0;
int dx = signx | (int) pkt[1];
int dy = signy | (int) pkt[2];
input_report_rel(psmouse->dev, REL_X, dx);
input_report_rel(psmouse->dev, REL_Y, -dy);
input_report_key(psmouse->dev, BTN_LEFT, pkt[0] & PS2_LEFT);
input_report_key(psmouse->dev, BTN_RIGHT, pkt[0] & PS2_RIGHT);
input_report_key(psmouse->dev, BTN_MIDDLE, pkt[0] & PS2_MIDDLE);
break;
}
case BYD_SCROLLDOWN:
case BYD_2DOWN:
input_report_rel(dev, REL_WHEEL, -1);
break;
case BYD_SCROLLUP:
case BYD_2UP:
input_report_rel(dev, REL_WHEEL, 1);
break;
case BYD_SCROLLLEFT:
case BYD_2LEFT:
input_report_rel(dev, REL_HWHEEL, -1);
break;
case BYD_SCROLLRIGHT:
case BYD_2RIGHT:
input_report_rel(dev, REL_HWHEEL, 1);
break;
case BYD_ZOOMOUT:
case BYD_ZOOMIN:
case BYD_3UP:
case BYD_3DOWN:
case BYD_3LEFT:
case BYD_3RIGHT:
case BYD_4UP:
case BYD_4DOWN:
break;
default:
psmouse_warn(psmouse,
"Unrecognized Z: pkt = %02x %02x %02x %02x\n",
psmouse->packet[0], psmouse->packet[1],
psmouse->packet[2], psmouse->packet[3]);
return PSMOUSE_BAD_DATA;
}
input_sync(dev);
return PSMOUSE_FULL_PACKET;
}
/* Send a sequence of bytes, where each is ACKed before the next is sent. */
static int byd_send_sequence(struct psmouse *psmouse, const u8 *seq, size_t len)
{
unsigned int i;
for (i = 0; i < len; ++i) {
if (ps2_command(&psmouse->ps2dev, NULL, seq[i]))
return -1;
}
return 0;
}
/* Keep scrolling after fingers are removed. */
#define SCROLL_INERTIAL 0x01
#define SCROLL_NO_INERTIAL 0x02
/* Clicking can be done by tapping or pressing. */
#define CLICK_BOTH 0x01
/* Clicking can only be done by pressing. */
#define CLICK_PRESS_ONLY 0x02
static int byd_enable(struct psmouse *psmouse)
{
const u8 seq1[] = { 0xE2, 0x00, 0xE0, 0x02, 0xE0 };
const u8 seq2[] = {
0xD3, 0x01,
0xD0, 0x00,
0xD0, 0x04,
/* Whether clicking is done by tapping or pressing. */
0xD4, CLICK_PRESS_ONLY,
0xD5, 0x01,
0xD7, 0x03,
/* Vertical and horizontal one-finger scroll zone inertia. */
0xD8, SCROLL_INERTIAL,
0xDA, 0x05,
0xDB, 0x02,
0xE4, 0x05,
0xD6, 0x01,
0xDE, 0x04,
0xE3, 0x01,
0xCF, 0x00,
0xD2, 0x03,
/* Vertical and horizontal two-finger scrolling inertia. */
0xE5, SCROLL_INERTIAL,
0xD9, 0x02,
0xD9, 0x07,
0xDC, 0x03,
0xDD, 0x03,
0xDF, 0x03,
0xE1, 0x03,
0xD1, 0x00,
0xCE, 0x00,
0xCC, 0x00,
0xE0, 0x00,
0xE2, 0x01
};
u8 param[4];
if (byd_send_sequence(psmouse, seq1, ARRAY_SIZE(seq1)))
return -1;
/* Send a 0x01 command, which should return 4 bytes. */
if (ps2_command(&psmouse->ps2dev, param, 0x0401))
return -1;
if (byd_send_sequence(psmouse, seq2, ARRAY_SIZE(seq2)))
return -1;
return 0;
}
/*
* Send the set of PS/2 commands required to make it identify as an
* intellimouse with 4-byte instead of 3-byte packets.
*/
static int byd_send_intellimouse_sequence(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
u8 param[4];
int i;
const struct {
u16 command;
u8 arg;
} seq[] = {
{ PSMOUSE_CMD_RESET_BAT, 0 },
{ PSMOUSE_CMD_RESET_BAT, 0 },
{ PSMOUSE_CMD_GETID, 0 },
{ PSMOUSE_CMD_SETSCALE11, 0 },
{ PSMOUSE_CMD_SETSCALE11, 0 },
{ PSMOUSE_CMD_SETSCALE11, 0 },
{ PSMOUSE_CMD_GETINFO, 0 },
{ PSMOUSE_CMD_SETRES, 0x03 },
{ PSMOUSE_CMD_SETRATE, 0xC8 },
{ PSMOUSE_CMD_SETRATE, 0x64 },
{ PSMOUSE_CMD_SETRATE, 0x50 },
{ PSMOUSE_CMD_GETID, 0 },
{ PSMOUSE_CMD_SETRATE, 0xC8 },
{ PSMOUSE_CMD_SETRATE, 0xC8 },
{ PSMOUSE_CMD_SETRATE, 0x50 },
{ PSMOUSE_CMD_GETID, 0 },
{ PSMOUSE_CMD_SETRATE, 0x64 },
{ PSMOUSE_CMD_SETRES, 0x03 },
{ PSMOUSE_CMD_ENABLE, 0 }
};
memset(param, 0, sizeof(param));
for (i = 0; i < ARRAY_SIZE(seq); ++i) {
param[0] = seq[i].arg;
if (ps2_command(ps2dev, param, seq[i].command))
return -1;
}
return 0;
}
static int byd_reset_touchpad(struct psmouse *psmouse)
{
if (byd_send_intellimouse_sequence(psmouse))
return -EIO;
if (byd_enable(psmouse))
return -EIO;
return 0;
}
static int byd_reconnect(struct psmouse *psmouse)
{
int retry = 0, error = 0;
psmouse_dbg(psmouse, "Reconnect\n");
do {
psmouse_reset(psmouse);
if (retry)
ssleep(1);
error = byd_detect(psmouse, 0);
} while (error && ++retry < 3);
if (error)
return error;
psmouse_dbg(psmouse, "Reconnected after %d attempts\n", retry);
error = byd_reset_touchpad(psmouse);
if (error) {
psmouse_err(psmouse, "Unable to initialize device\n");
return error;
}
return 0;
}
int byd_init(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
if (psmouse_reset(psmouse))
return -EIO;
if (byd_reset_touchpad(psmouse))
return -EIO;
psmouse->reconnect = byd_reconnect;
psmouse->protocol_handler = byd_process_byte;
psmouse->pktsize = 4;
psmouse->resync_time = 0;
__set_bit(BTN_MIDDLE, dev->keybit);
__set_bit(REL_WHEEL, dev->relbit);
__set_bit(REL_HWHEEL, dev->relbit);
return 0;
}
#ifndef _BYD_H
#define _BYD_H
#ifdef CONFIG_MOUSE_PS2_BYD
int byd_detect(struct psmouse *psmouse, bool set_properties);
int byd_init(struct psmouse *psmouse);
#else
static inline int byd_detect(struct psmouse *psmouse, bool set_properties)
{
return -ENOSYS;
}
static inline int byd_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
#endif /* CONFIG_MOUSE_PS2_BYD */
#endif /* _BYD_H */
......@@ -383,7 +383,7 @@ static int cyapa_open(struct input_dev *input)
* when in operational mode.
*/
error = cyapa->ops->set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
if (error) {
dev_warn(dev, "set active power failed: %d\n", error);
goto out;
......@@ -424,7 +424,8 @@ static void cyapa_close(struct input_dev *input)
pm_runtime_set_suspended(dev);
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false);
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
mutex_unlock(&cyapa->state_sync_lock);
}
......@@ -534,7 +535,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
*/
if (!input || cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
/* Gen3 always using polling mode for command. */
if (cyapa->gen >= CYAPA_GEN5)
enable_irq(cyapa->client->irq);
......@@ -550,7 +551,7 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
disable_irq(cyapa->client->irq);
if (!input || cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_OFF, 0, false);
PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
}
}
......@@ -617,7 +618,8 @@ static int cyapa_initialize(struct cyapa *cyapa)
/* Power down the device until we need it. */
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false);
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_OFF, 0, CYAPA_PM_ACTIVE);
return 0;
}
......@@ -634,7 +636,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa)
/* Avoid command failures when TP was in OFF state. */
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
error = cyapa_detect(cyapa);
if (error)
......@@ -654,7 +656,7 @@ static int cyapa_reinitialize(struct cyapa *cyapa)
/* Reset to power OFF state to save power when no user open. */
if (cyapa->operational)
cyapa->ops->set_power_mode(cyapa,
PWR_MODE_OFF, 0, false);
PWR_MODE_OFF, 0, CYAPA_PM_DEACTIVE);
} else if (!error && cyapa->operational) {
/*
* Make sure only enable runtime PM when device is
......@@ -1392,7 +1394,7 @@ static int __maybe_unused cyapa_suspend(struct device *dev)
power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode
: PWR_MODE_OFF;
error = cyapa->ops->set_power_mode(cyapa, power_mode,
cyapa->suspend_sleep_time, true);
cyapa->suspend_sleep_time, CYAPA_PM_SUSPEND);
if (error)
dev_err(dev, "suspend set power mode failed: %d\n",
error);
......@@ -1447,7 +1449,7 @@ static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
error = cyapa->ops->set_power_mode(cyapa,
cyapa->runtime_suspend_power_mode,
cyapa->runtime_suspend_sleep_time,
false);
CYAPA_PM_RUNTIME_SUSPEND);
if (error)
dev_warn(dev, "runtime suspend failed: %d\n", error);
......@@ -1460,7 +1462,7 @@ static int __maybe_unused cyapa_runtime_resume(struct device *dev)
int error;
error = cyapa->ops->set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_RUNTIME_RESUME);
if (error)
dev_warn(dev, "runtime resume failed: %d\n", error);
......
......@@ -250,6 +250,15 @@ struct cyapa;
typedef bool (*cb_sort)(struct cyapa *, u8 *, int);
enum cyapa_pm_stage {
CYAPA_PM_DEACTIVE,
CYAPA_PM_ACTIVE,
CYAPA_PM_SUSPEND,
CYAPA_PM_RESUME,
CYAPA_PM_RUNTIME_SUSPEND,
CYAPA_PM_RUNTIME_RESUME,
};
struct cyapa_dev_ops {
int (*check_fw)(struct cyapa *, const struct firmware *);
int (*bl_enter)(struct cyapa *);
......@@ -273,7 +282,7 @@ struct cyapa_dev_ops {
int (*sort_empty_output_data)(struct cyapa *,
u8 *, int *, cb_sort);
int (*set_power_mode)(struct cyapa *, u8, u16, bool);
int (*set_power_mode)(struct cyapa *, u8, u16, enum cyapa_pm_stage);
int (*set_proximity)(struct cyapa *, bool);
};
......@@ -289,6 +298,9 @@ struct cyapa_pip_cmd_states {
u8 *resp_data;
int *resp_len;
enum cyapa_pm_stage pm_stage;
struct mutex pm_stage_lock;
u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE];
u8 empty_buf[CYAPA_REG_MAP_SIZE];
};
......
......@@ -269,6 +269,7 @@ static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
{ CYAPA_SMBUS_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */
};
static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa);
/*
* cyapa_smbus_read_block - perform smbus block read command
......@@ -950,12 +951,14 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
* Device power mode can only be set when device is in operational mode.
*/
static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
u16 always_unused, bool is_suspend_unused)
u16 always_unused, enum cyapa_pm_stage pm_stage)
{
int ret;
struct input_dev *input = cyapa->input;
u8 power;
int tries;
u16 sleep_time;
int sleep_time;
int interval;
int ret;
if (cyapa->state != CYAPA_STATE_OP)
return 0;
......@@ -977,7 +980,7 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
if ((ret & PWR_MODE_MASK) == power_mode)
return 0;
sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
sleep_time = (int)cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
power = ret;
power &= ~PWR_MODE_MASK;
power |= power_mode & PWR_MODE_MASK;
......@@ -995,7 +998,23 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
* doing so before issuing the next command may result in errors
* depending on the command's content.
*/
msleep(sleep_time);
if (cyapa->operational && input && input->users &&
(pm_stage == CYAPA_PM_RUNTIME_SUSPEND ||
pm_stage == CYAPA_PM_RUNTIME_RESUME)) {
/* Try to polling in 120Hz, read may fail, just ignore it. */
interval = 1000 / 120;
while (sleep_time > 0) {
if (sleep_time > interval)
msleep(interval);
else
msleep(sleep_time);
sleep_time -= interval;
cyapa_gen3_try_poll_handler(cyapa);
}
} else {
msleep(sleep_time);
}
return ret;
}
......@@ -1112,7 +1131,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
* may cause problems, so we set the power mode first here.
*/
error = cyapa_gen3_set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
if (error)
dev_err(dev, "%s: set full power mode failed: %d\n",
__func__, error);
......@@ -1168,32 +1187,16 @@ static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa)
return false;
}
static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
static int cyapa_gen3_event_process(struct cyapa *cyapa,
struct cyapa_reg_data *data)
{
struct input_dev *input = cyapa->input;
struct device *dev = &cyapa->client->dev;
struct cyapa_reg_data data;
int num_fingers;
int ret;
int i;
ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
if (ret != sizeof(data)) {
dev_err(dev, "failed to read report data, (%d)\n", ret);
return -EINVAL;
}
if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
(data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
(data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
dev_err(dev, "invalid device state bytes, %02x %02x\n",
data.device_status, data.finger_btn);
return -EINVAL;
}
num_fingers = (data.finger_btn >> 4) & 0x0f;
num_fingers = (data->finger_btn >> 4) & 0x0f;
for (i = 0; i < num_fingers; i++) {
const struct cyapa_touch *touch = &data.touches[i];
const struct cyapa_touch *touch = &data->touches[i];
/* Note: touch->id range is 1 to 15; slots are 0 to 14. */
int slot = touch->id - 1;
......@@ -1210,18 +1213,65 @@ static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
input_report_key(input, BTN_LEFT,
!!(data.finger_btn & OP_DATA_LEFT_BTN));
!!(data->finger_btn & OP_DATA_LEFT_BTN));
if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
input_report_key(input, BTN_MIDDLE,
!!(data.finger_btn & OP_DATA_MIDDLE_BTN));
!!(data->finger_btn & OP_DATA_MIDDLE_BTN));
if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
input_report_key(input, BTN_RIGHT,
!!(data.finger_btn & OP_DATA_RIGHT_BTN));
!!(data->finger_btn & OP_DATA_RIGHT_BTN));
input_sync(input);
return 0;
}
static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
{
struct device *dev = &cyapa->client->dev;
struct cyapa_reg_data data;
int ret;
ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
if (ret != sizeof(data)) {
dev_err(dev, "failed to read report data, (%d)\n", ret);
return -EINVAL;
}
if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
(data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
(data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
dev_err(dev, "invalid device state bytes: %02x %02x\n",
data.device_status, data.finger_btn);
return -EINVAL;
}
return cyapa_gen3_event_process(cyapa, &data);
}
/*
* This function will be called in the cyapa_gen3_set_power_mode function,
* and it's known that it may failed in some situation after the set power
* mode command was sent. So this function is aimed to avoid the knwon
* and unwanted output I2C and data parse error messages.
*/
static int cyapa_gen3_try_poll_handler(struct cyapa *cyapa)
{
struct cyapa_reg_data data;
int ret;
ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
if (ret != sizeof(data))
return -EINVAL;
if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
(data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
(data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID)
return -EINVAL;
return cyapa_gen3_event_process(cyapa, &data);
}
static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; }
static int cyapa_gen3_bl_initiate(struct cyapa *cyapa,
const struct firmware *fw) { return 0; }
......
......@@ -342,6 +342,9 @@ u8 pip_bl_read_app_info[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
0xff, 0xfe, 0xfd, 0x5a };
static int cyapa_pip_event_process(struct cyapa *cyapa,
struct cyapa_pip_report_data *report_data);
int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa)
{
struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
......@@ -350,6 +353,9 @@ int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa)
atomic_set(&pip->cmd_issued, 0);
mutex_init(&pip->cmd_lock);
mutex_init(&pip->pm_stage_lock);
pip->pm_stage = CYAPA_PM_DEACTIVE;
pip->resp_sort_func = NULL;
pip->in_progress_cmd = PIP_INVALID_CMD;
pip->resp_data = NULL;
......@@ -397,6 +403,38 @@ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
return 0;
}
static void cyapa_set_pip_pm_state(struct cyapa *cyapa,
enum cyapa_pm_stage pm_stage)
{
struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
mutex_lock(&pip->pm_stage_lock);
pip->pm_stage = pm_stage;
mutex_unlock(&pip->pm_stage_lock);
}
static void cyapa_reset_pip_pm_state(struct cyapa *cyapa)
{
struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
/* Indicates the pip->pm_stage is not valid. */
mutex_lock(&pip->pm_stage_lock);
pip->pm_stage = CYAPA_PM_DEACTIVE;
mutex_unlock(&pip->pm_stage_lock);
}
static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa)
{
struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
enum cyapa_pm_stage pm_stage;
mutex_lock(&pip->pm_stage_lock);
pm_stage = pip->pm_stage;
mutex_unlock(&pip->pm_stage_lock);
return pm_stage;
}
/**
* This function is aimed to dump all not read data in Gen5 trackpad
* before send any command, otherwise, the interrupt line will be blocked.
......@@ -404,7 +442,9 @@ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
int cyapa_empty_pip_output_data(struct cyapa *cyapa,
u8 *buf, int *len, cb_sort func)
{
struct input_dev *input = cyapa->input;
struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip;
enum cyapa_pm_stage pm_stage = cyapa_get_pip_pm_state(cyapa);
int length;
int report_count;
int empty_count;
......@@ -478,6 +518,12 @@ int cyapa_empty_pip_output_data(struct cyapa *cyapa,
*len = length;
/* Response found, success. */
return 0;
} else if (cyapa->operational && input && input->users &&
(pm_stage == CYAPA_PM_RUNTIME_RESUME ||
pm_stage == CYAPA_PM_RUNTIME_SUSPEND)) {
/* Parse the data and report it if it's valid. */
cyapa_pip_event_process(cyapa,
(struct cyapa_pip_report_data *)pip->empty_buf);
}
error = -EINVAL;
......@@ -1566,15 +1612,17 @@ int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state)
}
static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
u8 power_mode, u16 sleep_time, bool is_suspend)
u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
{
struct device *dev = &cyapa->client->dev;
u8 power_state;
int error;
int error = 0;
if (cyapa->state != CYAPA_STATE_GEN5_APP)
return 0;
cyapa_set_pip_pm_state(cyapa, pm_stage);
if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
/*
* Assume TP in deep sleep mode when driver is loaded,
......@@ -1597,7 +1645,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
power_mode == PWR_MODE_BTN_ONLY ||
PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
/* Has in correct power mode state, early return. */
return 0;
goto out;
}
}
......@@ -1605,11 +1653,11 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF);
if (error) {
dev_err(dev, "enter deep sleep fail: %d\n", error);
return error;
goto out;
}
PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
return 0;
goto out;
}
/*
......@@ -1621,7 +1669,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON);
if (error) {
dev_err(dev, "deep sleep wake fail: %d\n", error);
return error;
goto out;
}
}
......@@ -1630,7 +1678,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
GEN5_POWER_STATE_ACTIVE);
if (error) {
dev_err(dev, "change to active fail: %d\n", error);
return error;
goto out;
}
PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
......@@ -1639,7 +1687,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
GEN5_POWER_STATE_BTN_ONLY);
if (error) {
dev_err(dev, "fail to button only mode: %d\n", error);
return error;
goto out;
}
PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
......@@ -1664,7 +1712,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
if (error) {
dev_err(dev, "set power state to 0x%02x failed: %d\n",
power_state, error);
return error;
goto out;
}
/*
......@@ -1677,14 +1725,16 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
* is suspending which may cause interrupt line unable to be
* asserted again.
*/
if (is_suspend)
if (pm_stage == CYAPA_PM_SUSPEND)
cyapa_gen5_disable_pip_report(cyapa);
PIP_DEV_SET_PWR_STATE(cyapa,
cyapa_sleep_time_to_pwr_cmd(sleep_time));
}
return 0;
out:
cyapa_reset_pip_pm_state(cyapa);
return error;
}
int cyapa_pip_resume_scanning(struct cyapa *cyapa)
......@@ -2513,7 +2563,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
* the device state is required.
*/
error = cyapa_gen5_set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
if (error)
dev_warn(dev, "%s: failed to set power active mode.\n",
__func__);
......@@ -2715,7 +2765,6 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa)
struct device *dev = &cyapa->client->dev;
struct cyapa_pip_report_data report_data;
unsigned int report_len;
u8 report_id;
int ret;
if (!cyapa_is_pip_app_mode(cyapa)) {
......@@ -2752,7 +2801,23 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa)
return -EINVAL;
}
report_id = report_data.report_head[PIP_RESP_REPORT_ID_OFFSET];
return cyapa_pip_event_process(cyapa, &report_data);
}
static int cyapa_pip_event_process(struct cyapa *cyapa,
struct cyapa_pip_report_data *report_data)
{
struct device *dev = &cyapa->client->dev;
unsigned int report_len;
u8 report_id;
report_len = get_unaligned_le16(
&report_data->report_head[PIP_RESP_LENGTH_OFFSET]);
/* Idle, no data for report. */
if (report_len == PIP_RESP_LENGTH_SIZE)
return 0;
report_id = report_data->report_head[PIP_RESP_REPORT_ID_OFFSET];
if (report_id == PIP_WAKEUP_EVENT_REPORT_ID &&
report_len == PIP_WAKEUP_EVENT_SIZE) {
/*
......@@ -2805,11 +2870,11 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa)
}
if (report_id == PIP_TOUCH_REPORT_ID)
cyapa_pip_report_touches(cyapa, &report_data);
cyapa_pip_report_touches(cyapa, report_data);
else if (report_id == PIP_PROXIMITY_REPORT_ID)
cyapa_pip_report_proximity(cyapa, &report_data);
cyapa_pip_report_proximity(cyapa, report_data);
else
cyapa_pip_report_buttons(cyapa, &report_data);
cyapa_pip_report_buttons(cyapa, report_data);
return 0;
}
......
......@@ -425,7 +425,7 @@ static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state)
}
static int cyapa_gen6_set_power_mode(struct cyapa *cyapa,
u8 power_mode, u16 sleep_time, bool is_suspend)
u8 power_mode, u16 sleep_time, enum cyapa_pm_stage pm_stage)
{
struct device *dev = &cyapa->client->dev;
struct gen6_interval_setting *interval_setting =
......@@ -689,7 +689,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa)
* the device state is required.
*/
error = cyapa_gen6_set_power_mode(cyapa,
PWR_MODE_FULL_ACTIVE, 0, false);
PWR_MODE_FULL_ACTIVE, 0, CYAPA_PM_ACTIVE);
if (error)
dev_warn(dev, "%s: failed to set power active mode.\n",
__func__);
......
......@@ -37,6 +37,7 @@
#include "cypress_ps2.h"
#include "focaltech.h"
#include "vmmouse.h"
#include "byd.h"
#define DRIVER_DESC "PS/2 mouse driver"
......@@ -841,6 +842,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = vmmouse_detect,
.init = vmmouse_init,
},
#endif
#ifdef CONFIG_MOUSE_PS2_BYD
{
.type = PSMOUSE_BYD,
.name = "BydPS/2",
.alias = "byd",
.detect = byd_detect,
.init = byd_init,
},
#endif
{
.type = PSMOUSE_AUTO,
......@@ -1105,6 +1115,10 @@ static int psmouse_extensions(struct psmouse *psmouse,
if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2,
&max_proto, set_properties, true))
return PSMOUSE_TOUCHKIT_PS2;
if (psmouse_try_protocol(psmouse, PSMOUSE_BYD,
&max_proto, set_properties, true))
return PSMOUSE_BYD;
}
/*
......
......@@ -104,6 +104,7 @@ enum psmouse_type {
PSMOUSE_CYPRESS,
PSMOUSE_FOCALTECH,
PSMOUSE_VMMOUSE,
PSMOUSE_BYD,
PSMOUSE_AUTO /* This one should always be last */
};
......
#
# RMI4 configuration
#
config RMI4_CORE
tristate "Synaptics RMI4 bus support"
help
Say Y here if you want to support the Synaptics RMI4 bus. This is
required for all RMI4 device support.
If unsure, say Y.
config RMI4_I2C
tristate "RMI4 I2C Support"
depends on RMI4_CORE && I2C
help
Say Y here if you want to support RMI4 devices connected to an I2C
bus.
If unsure, say Y.
config RMI4_SPI
tristate "RMI4 SPI Support"
depends on RMI4_CORE && SPI
help
Say Y here if you want to support RMI4 devices connected to a SPI
bus.
If unsure, say N.
config RMI4_2D_SENSOR
bool
depends on RMI4_CORE
config RMI4_F11
bool "RMI4 Function 11 (2D pointing)"
select RMI4_2D_SENSOR
depends on RMI4_CORE
help
Say Y here if you want to add support for RMI4 function 11.
Function 11 provides 2D multifinger pointing for touchscreens and
touchpads. For sensors that support relative pointing, F11 also
provides mouse input.
config RMI4_F12
bool "RMI4 Function 12 (2D pointing)"
select RMI4_2D_SENSOR
depends on RMI4_CORE
help
Say Y here if you want to add support for RMI4 function 12.
Function 12 provides 2D multifinger pointing for touchscreens and
touchpads. For sensors that support relative pointing, F12 also
provides mouse input.
config RMI4_F30
bool "RMI4 Function 30 (GPIO LED)"
depends on RMI4_CORE
help
Say Y here if you want to add support for RMI4 function 30.
Function 30 provides GPIO and LED support for RMI4 devices. This
includes support for buttons on TouchPads and ClickPads.
obj-$(CONFIG_RMI4_CORE) += rmi_core.o
rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
# Function drivers
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
# Transports
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#include "rmi_2d_sensor.h"
#define RMI_2D_REL_POS_MIN -128
#define RMI_2D_REL_POS_MAX 127
/* maximum ABS_MT_POSITION displacement (in mm) */
#define DMAX 10
void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
/* we keep the previous values if the finger is released */
if (obj->type == RMI_2D_OBJECT_NONE)
return;
if (axis_align->swap_axes)
swap(obj->x, obj->y);
if (axis_align->flip_x)
obj->x = sensor->max_x - obj->x;
if (axis_align->flip_y)
obj->y = sensor->max_y - obj->y;
/*
* Here checking if X offset or y offset are specified is
* redundant. We just add the offsets or clip the values.
*
* Note: offsets need to be applied before clipping occurs,
* or we could get funny values that are outside of
* clipping boundaries.
*/
obj->x += axis_align->offset_x;
obj->y += axis_align->offset_y;
obj->x = max(axis_align->clip_x_low, obj->x);
obj->y = max(axis_align->clip_y_low, obj->y);
if (axis_align->clip_x_high)
obj->x = min(sensor->max_x, obj->x);
if (axis_align->clip_y_high)
obj->y = min(sensor->max_y, obj->y);
sensor->tracking_pos[slot].x = obj->x;
sensor->tracking_pos[slot].y = obj->y;
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_process);
void rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
struct input_dev *input = sensor->input;
int wide, major, minor;
if (sensor->kernel_tracking)
input_mt_slot(input, sensor->tracking_slots[slot]);
else
input_mt_slot(input, slot);
input_mt_report_slot_state(input, obj->mt_tool,
obj->type != RMI_2D_OBJECT_NONE);
if (obj->type != RMI_2D_OBJECT_NONE) {
obj->x = sensor->tracking_pos[slot].x;
obj->y = sensor->tracking_pos[slot].y;
if (axis_align->swap_axes)
swap(obj->wx, obj->wy);
wide = (obj->wx > obj->wy);
major = max(obj->wx, obj->wy);
minor = min(obj->wx, obj->wy);
if (obj->type == RMI_2D_OBJECT_STYLUS) {
major = max(1, major);
minor = max(1, minor);
}
input_event(sensor->input, EV_ABS, ABS_MT_POSITION_X, obj->x);
input_event(sensor->input, EV_ABS, ABS_MT_POSITION_Y, obj->y);
input_event(sensor->input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(sensor->input, EV_ABS, ABS_MT_PRESSURE, obj->z);
input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
rmi_dbg(RMI_DEBUG_2D_SENSOR, &sensor->input->dev,
"%s: obj[%d]: type: 0x%02x X: %d Y: %d Z: %d WX: %d WY: %d\n",
__func__, slot, obj->type, obj->x, obj->y, obj->z,
obj->wx, obj->wy);
}
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_report);
void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x));
y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y));
if (axis_align->swap_axes)
swap(x, y);
if (axis_align->flip_x)
x = min(RMI_2D_REL_POS_MAX, -x);
if (axis_align->flip_y)
y = min(RMI_2D_REL_POS_MAX, -y);
if (x || y) {
input_report_rel(sensor->input, REL_X, x);
input_report_rel(sensor->input, REL_Y, y);
}
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_rel_report);
static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
{
struct input_dev *input = sensor->input;
int res_x;
int res_y;
int input_flags = 0;
if (sensor->report_abs) {
if (sensor->axis_align.swap_axes)
swap(sensor->max_x, sensor->max_y);
sensor->min_x = sensor->axis_align.clip_x_low;
if (sensor->axis_align.clip_x_high)
sensor->max_x = min(sensor->max_x,
sensor->axis_align.clip_x_high);
sensor->min_y = sensor->axis_align.clip_y_low;
if (sensor->axis_align.clip_y_high)
sensor->max_y = min(sensor->max_y,
sensor->axis_align.clip_y_high);
set_bit(EV_ABS, input->evbit);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, sensor->max_x,
0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, sensor->max_y,
0, 0);
if (sensor->x_mm && sensor->y_mm) {
res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm;
res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm;
input_abs_set_res(input, ABS_X, res_x);
input_abs_set_res(input, ABS_Y, res_y);
input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
if (!sensor->dmax)
sensor->dmax = DMAX * res_x;
}
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
if (sensor->sensor_type == rmi_sensor_touchpad)
input_flags = INPUT_MT_POINTER;
else
input_flags = INPUT_MT_DIRECT;
if (sensor->kernel_tracking)
input_flags |= INPUT_MT_TRACK;
input_mt_init_slots(input, sensor->nbr_fingers, input_flags);
}
if (sensor->report_rel) {
set_bit(EV_REL, input->evbit);
set_bit(REL_X, input->relbit);
set_bit(REL_Y, input->relbit);
}
if (sensor->topbuttonpad)
set_bit(INPUT_PROP_TOPBUTTONPAD, input->propbit);
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_set_input_params);
int rmi_2d_sensor_configure_input(struct rmi_function *fn,
struct rmi_2d_sensor *sensor)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
if (!drv_data->input)
return -ENODEV;
sensor->input = drv_data->input;
rmi_2d_sensor_set_input_params(sensor);
return 0;
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_configure_input);
#ifdef CONFIG_OF
int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata)
{
int retval;
u32 val;
pdata->axis_align.swap_axes = of_property_read_bool(dev->of_node,
"touchscreen-swapped-x-y");
pdata->axis_align.flip_x = of_property_read_bool(dev->of_node,
"touchscreen-inverted-x");
pdata->axis_align.flip_y = of_property_read_bool(dev->of_node,
"touchscreen-inverted-y");
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-low", 1);
if (retval)
return retval;
pdata->axis_align.clip_x_low = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-low", 1);
if (retval)
return retval;
pdata->axis_align.clip_y_low = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-high", 1);
if (retval)
return retval;
pdata->axis_align.clip_x_high = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-high", 1);
if (retval)
return retval;
pdata->axis_align.clip_y_high = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,offset-x", 1);
if (retval)
return retval;
pdata->axis_align.offset_x = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,offset-y", 1);
if (retval)
return retval;
pdata->axis_align.offset_y = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,delta-x-threshold",
1);
if (retval)
return retval;
pdata->axis_align.delta_x_threshold = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,delta-y-threshold",
1);
if (retval)
return retval;
pdata->axis_align.delta_y_threshold = val;
retval = rmi_of_property_read_u32(dev, (u32 *)&pdata->sensor_type,
"syna,sensor-type", 1);
if (retval)
return retval;
retval = rmi_of_property_read_u32(dev, &val, "touchscreen-x-mm", 1);
if (retval)
return retval;
pdata->x_mm = val;
retval = rmi_of_property_read_u32(dev, &val, "touchscreen-y-mm", 1);
if (retval)
return retval;
pdata->y_mm = val;
retval = rmi_of_property_read_u32(dev, &val,
"syna,disable-report-mask", 1);
if (retval)
return retval;
pdata->disable_report_mask = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,rezero-wait-ms",
1);
if (retval)
return retval;
pdata->rezero_wait = val;
return 0;
}
#else
inline int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata)
{
return -ENODEV;
}
#endif
EXPORT_SYMBOL_GPL(rmi_2d_sensor_of_probe);
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _RMI_2D_SENSOR_H
#define _RMI_2D_SENSOR_H
enum rmi_2d_sensor_object_type {
RMI_2D_OBJECT_NONE,
RMI_2D_OBJECT_FINGER,
RMI_2D_OBJECT_STYLUS,
RMI_2D_OBJECT_PALM,
RMI_2D_OBJECT_UNCLASSIFIED,
};
struct rmi_2d_sensor_abs_object {
enum rmi_2d_sensor_object_type type;
int mt_tool;
u16 x;
u16 y;
u8 z;
u8 wx;
u8 wy;
};
/**
* @axis_align - controls parameters that are useful in system prototyping
* and bring up.
* @max_x - The maximum X coordinate that will be reported by this sensor.
* @max_y - The maximum Y coordinate that will be reported by this sensor.
* @nbr_fingers - How many fingers can this sensor report?
* @data_pkt - buffer for data reported by this sensor.
* @pkt_size - number of bytes in that buffer.
* @attn_size - Size of the HID attention report (only contains abs data).
* position when two fingers are on the device. When this is true, we
* assume we have one of those sensors and report events appropriately.
* @sensor_type - indicates whether we're touchscreen or touchpad.
* @input - input device for absolute pointing stream
* @input_phys - buffer for the absolute phys name for this sensor.
*/
struct rmi_2d_sensor {
struct rmi_2d_axis_alignment axis_align;
struct input_mt_pos *tracking_pos;
int *tracking_slots;
bool kernel_tracking;
struct rmi_2d_sensor_abs_object *objs;
int dmax;
u16 min_x;
u16 max_x;
u16 min_y;
u16 max_y;
u8 nbr_fingers;
u8 *data_pkt;
int pkt_size;
int attn_size;
bool topbuttonpad;
enum rmi_sensor_type sensor_type;
struct input_dev *input;
struct rmi_function *fn;
char input_phys[32];
u8 report_abs;
u8 report_rel;
u8 x_mm;
u8 y_mm;
};
int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata);
void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot);
void rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot);
void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y);
int rmi_2d_sensor_configure_input(struct rmi_function *fn,
struct rmi_2d_sensor *sensor);
#endif /* _RMI_2D_SENSOR_H */
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/kconfig.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/of.h>
#include "rmi_bus.h"
#include "rmi_driver.h"
static int debug_flags;
module_param(debug_flags, int, 0644);
MODULE_PARM_DESC(debug_flags, "control debugging information");
void rmi_dbg(int flags, struct device *dev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
if (flags & debug_flags) {
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
dev_printk(KERN_DEBUG, dev, "%pV", &vaf);
va_end(args);
}
}
EXPORT_SYMBOL_GPL(rmi_dbg);
/*
* RMI Physical devices
*
* Physical RMI device consists of several functions serving particular
* purpose. For example F11 is a 2D touch sensor while F01 is a generic
* function present in every RMI device.
*/
static void rmi_release_device(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
kfree(rmi_dev);
}
static struct device_type rmi_device_type = {
.name = "rmi4_sensor",
.release = rmi_release_device,
};
bool rmi_is_physical_device(struct device *dev)
{
return dev->type == &rmi_device_type;
}
/**
* rmi_register_transport_device - register a transport device connection
* on the RMI bus. Transport drivers provide communication from the devices
* on a bus (such as SPI, I2C, and so on) to the RMI4 sensor.
*
* @xport: the transport device to register
*/
int rmi_register_transport_device(struct rmi_transport_dev *xport)
{
static atomic_t transport_device_count = ATOMIC_INIT(0);
struct rmi_device *rmi_dev;
int error;
rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
if (!rmi_dev)
return -ENOMEM;
device_initialize(&rmi_dev->dev);
rmi_dev->xport = xport;
rmi_dev->number = atomic_inc_return(&transport_device_count) - 1;
dev_set_name(&rmi_dev->dev, "rmi4-%02d", rmi_dev->number);
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->dev.type = &rmi_device_type;
xport->rmi_dev = rmi_dev;
error = device_add(&rmi_dev->dev);
if (error)
goto err_put_device;
rmi_dbg(RMI_DEBUG_CORE, xport->dev,
"%s: Registered %s as %s.\n", __func__,
dev_name(rmi_dev->xport->dev), dev_name(&rmi_dev->dev));
return 0;
err_put_device:
put_device(&rmi_dev->dev);
return error;
}
EXPORT_SYMBOL_GPL(rmi_register_transport_device);
/**
* rmi_unregister_transport_device - unregister a transport device connection
* @xport: the transport driver to unregister
*
*/
void rmi_unregister_transport_device(struct rmi_transport_dev *xport)
{
struct rmi_device *rmi_dev = xport->rmi_dev;
device_del(&rmi_dev->dev);
put_device(&rmi_dev->dev);
}
EXPORT_SYMBOL(rmi_unregister_transport_device);
/* Function specific stuff */
static void rmi_release_function(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
kfree(fn);
}
static struct device_type rmi_function_type = {
.name = "rmi4_function",
.release = rmi_release_function,
};
bool rmi_is_function_device(struct device *dev)
{
return dev->type == &rmi_function_type;
}
static int rmi_function_match(struct device *dev, struct device_driver *drv)
{
struct rmi_function_handler *handler = to_rmi_function_handler(drv);
struct rmi_function *fn = to_rmi_function(dev);
return fn->fd.function_number == handler->func;
}
#ifdef CONFIG_OF
static void rmi_function_of_probe(struct rmi_function *fn)
{
char of_name[9];
snprintf(of_name, sizeof(of_name), "rmi4-f%02x",
fn->fd.function_number);
fn->dev.of_node = of_find_node_by_name(
fn->rmi_dev->xport->dev->of_node, of_name);
}
#else
static inline void rmi_function_of_probe(struct rmi_function *fn)
{}
#endif
static int rmi_function_probe(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_function_handler *handler =
to_rmi_function_handler(dev->driver);
int error;
rmi_function_of_probe(fn);
if (handler->probe) {
error = handler->probe(fn);
return error;
}
return 0;
}
static int rmi_function_remove(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_function_handler *handler =
to_rmi_function_handler(dev->driver);
if (handler->remove)
handler->remove(fn);
return 0;
}
int rmi_register_function(struct rmi_function *fn)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
int error;
device_initialize(&fn->dev);
dev_set_name(&fn->dev, "%s.fn%02x",
dev_name(&rmi_dev->dev), fn->fd.function_number);
fn->dev.parent = &rmi_dev->dev;
fn->dev.type = &rmi_function_type;
fn->dev.bus = &rmi_bus_type;
error = device_add(&fn->dev);
if (error) {
dev_err(&rmi_dev->dev,
"Failed device_register function device %s\n",
dev_name(&fn->dev));
goto err_put_device;
}
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Registered F%02X.\n",
fn->fd.function_number);
return 0;
err_put_device:
put_device(&fn->dev);
return error;
}
void rmi_unregister_function(struct rmi_function *fn)
{
device_del(&fn->dev);
if (fn->dev.of_node)
of_node_put(fn->dev.of_node);
put_device(&fn->dev);
}
/**
* rmi_register_function_handler - register a handler for an RMI function
* @handler: RMI handler that should be registered.
* @module: pointer to module that implements the handler
* @mod_name: name of the module implementing the handler
*
* This function performs additional setup of RMI function handler and
* registers it with the RMI core so that it can be bound to
* RMI function devices.
*/
int __rmi_register_function_handler(struct rmi_function_handler *handler,
struct module *owner,
const char *mod_name)
{
struct device_driver *driver = &handler->driver;
int error;
driver->bus = &rmi_bus_type;
driver->owner = owner;
driver->mod_name = mod_name;
driver->probe = rmi_function_probe;
driver->remove = rmi_function_remove;
error = driver_register(&handler->driver);
if (error) {
pr_err("driver_register() failed for %s, error: %d\n",
handler->driver.name, error);
return error;
}
return 0;
}
EXPORT_SYMBOL_GPL(__rmi_register_function_handler);
/**
* rmi_unregister_function_handler - unregister given RMI function handler
* @handler: RMI handler that should be unregistered.
*
* This function unregisters given function handler from RMI core which
* causes it to be unbound from the function devices.
*/
void rmi_unregister_function_handler(struct rmi_function_handler *handler)
{
driver_unregister(&handler->driver);
}
EXPORT_SYMBOL_GPL(rmi_unregister_function_handler);
/* Bus specific stuff */
static int rmi_bus_match(struct device *dev, struct device_driver *drv)
{
bool physical = rmi_is_physical_device(dev);
/* First see if types are not compatible */
if (physical != rmi_is_physical_driver(drv))
return 0;
return physical || rmi_function_match(dev, drv);
}
struct bus_type rmi_bus_type = {
.match = rmi_bus_match,
.name = "rmi4",
};
static struct rmi_function_handler *fn_handlers[] = {
&rmi_f01_handler,
#ifdef CONFIG_RMI4_F11
&rmi_f11_handler,
#endif
#ifdef CONFIG_RMI4_F12
&rmi_f12_handler,
#endif
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
};
static void __rmi_unregister_function_handlers(int start_idx)
{
int i;
for (i = start_idx; i >= 0; i--)
rmi_unregister_function_handler(fn_handlers[i]);
}
static void rmi_unregister_function_handlers(void)
{
__rmi_unregister_function_handlers(ARRAY_SIZE(fn_handlers) - 1);
}
static int rmi_register_function_handlers(void)
{
int ret;
int i;
for (i = 0; i < ARRAY_SIZE(fn_handlers); i++) {
ret = rmi_register_function_handler(fn_handlers[i]);
if (ret) {
pr_err("%s: error registering the RMI F%02x handler: %d\n",
__func__, fn_handlers[i]->func, ret);
goto err_unregister_function_handlers;
}
}
return 0;
err_unregister_function_handlers:
__rmi_unregister_function_handlers(i - 1);
return ret;
}
int rmi_of_property_read_u32(struct device *dev, u32 *result,
const char *prop, bool optional)
{
int retval;
u32 val = 0;
retval = of_property_read_u32(dev->of_node, prop, &val);
if (retval && (!optional && retval == -EINVAL)) {
dev_err(dev, "Failed to get %s value: %d\n",
prop, retval);
return retval;
}
*result = val;
return 0;
}
EXPORT_SYMBOL_GPL(rmi_of_property_read_u32);
static int __init rmi_bus_init(void)
{
int error;
error = bus_register(&rmi_bus_type);
if (error) {
pr_err("%s: error registering the RMI bus: %d\n",
__func__, error);
return error;
}
error = rmi_register_function_handlers();
if (error)
goto err_unregister_bus;
error = rmi_register_physical_driver();
if (error) {
pr_err("%s: error registering the RMI physical driver: %d\n",
__func__, error);
goto err_unregister_bus;
}
return 0;
err_unregister_bus:
bus_unregister(&rmi_bus_type);
return error;
}
module_init(rmi_bus_init);
static void __exit rmi_bus_exit(void)
{
/*
* We should only ever get here if all drivers are unloaded, so
* all we have to do at this point is unregister ourselves.
*/
rmi_unregister_physical_driver();
rmi_unregister_function_handlers();
bus_unregister(&rmi_bus_type);
}
module_exit(rmi_bus_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com");
MODULE_DESCRIPTION("RMI bus");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _RMI_BUS_H
#define _RMI_BUS_H
#include <linux/rmi.h>
struct rmi_device;
/**
* struct rmi_function - represents the implementation of an RMI4
* function for a particular device (basically, a driver for that RMI4 function)
*
* @fd: The function descriptor of the RMI function
* @rmi_dev: Pointer to the RMI device associated with this function container
* @dev: The device associated with this particular function.
*
* @num_of_irqs: The number of irqs needed by this function
* @irq_pos: The position in the irq bitfield this function holds
* @irq_mask: For convenience, can be used to mask IRQ bits off during ATTN
* interrupt handling.
*
* @node: entry in device's list of functions
*/
struct rmi_function {
struct rmi_function_descriptor fd;
struct rmi_device *rmi_dev;
struct device dev;
struct list_head node;
unsigned int num_of_irqs;
unsigned int irq_pos;
unsigned long irq_mask[];
};
#define to_rmi_function(d) container_of(d, struct rmi_function, dev)
bool rmi_is_function_device(struct device *dev);
int __must_check rmi_register_function(struct rmi_function *);
void rmi_unregister_function(struct rmi_function *);
/**
* struct rmi_function_handler - driver routines for a particular RMI function.
*
* @func: The RMI function number
* @reset: Called when a reset of the touch sensor is detected. The routine
* should perform any out-of-the-ordinary reset handling that might be
* necessary. Restoring of touch sensor configuration registers should be
* handled in the config() callback, below.
* @config: Called when the function container is first initialized, and
* after a reset is detected. This routine should write any necessary
* configuration settings to the device.
* @attention: Called when the IRQ(s) for the function are set by the touch
* sensor.
* @suspend: Should perform any required operations to suspend the particular
* function.
* @resume: Should perform any required operations to resume the particular
* function.
*
* All callbacks are expected to return 0 on success, error code on failure.
*/
struct rmi_function_handler {
struct device_driver driver;
u8 func;
int (*probe)(struct rmi_function *fn);
void (*remove)(struct rmi_function *fn);
int (*config)(struct rmi_function *fn);
int (*reset)(struct rmi_function *fn);
int (*attention)(struct rmi_function *fn, unsigned long *irq_bits);
int (*suspend)(struct rmi_function *fn);
int (*resume)(struct rmi_function *fn);
};
#define to_rmi_function_handler(d) \
container_of(d, struct rmi_function_handler, driver)
int __must_check __rmi_register_function_handler(struct rmi_function_handler *,
struct module *, const char *);
#define rmi_register_function_handler(handler) \
__rmi_register_function_handler(handler, THIS_MODULE, KBUILD_MODNAME)
void rmi_unregister_function_handler(struct rmi_function_handler *);
#define to_rmi_driver(d) \
container_of(d, struct rmi_driver, driver)
#define to_rmi_device(d) container_of(d, struct rmi_device, dev)
static inline struct rmi_device_platform_data *
rmi_get_platform_data(struct rmi_device *d)
{
return &d->xport->pdata;
}
bool rmi_is_physical_device(struct device *dev);
/**
* rmi_read - read a single byte
* @d: Pointer to an RMI device
* @addr: The address to read from
* @buf: The read buffer
*
* Reads a single byte of data using the underlying transport protocol
* into memory pointed by @buf. It returns 0 on success or a negative
* error code.
*/
static inline int rmi_read(struct rmi_device *d, u16 addr, u8 *buf)
{
return d->xport->ops->read_block(d->xport, addr, buf, 1);
}
/**
* rmi_read_block - read a block of bytes
* @d: Pointer to an RMI device
* @addr: The start address to read from
* @buf: The read buffer
* @len: Length of the read buffer
*
* Reads a block of byte data using the underlying transport protocol
* into memory pointed by @buf. It returns 0 on success or a negative
* error code.
*/
static inline int rmi_read_block(struct rmi_device *d, u16 addr,
void *buf, size_t len)
{
return d->xport->ops->read_block(d->xport, addr, buf, len);
}
/**
* rmi_write - write a single byte
* @d: Pointer to an RMI device
* @addr: The address to write to
* @data: The data to write
*
* Writes a single byte using the underlying transport protocol. It
* returns zero on success or a negative error code.
*/
static inline int rmi_write(struct rmi_device *d, u16 addr, u8 data)
{
return d->xport->ops->write_block(d->xport, addr, &data, 1);
}
/**
* rmi_write_block - write a block of bytes
* @d: Pointer to an RMI device
* @addr: The start address to write to
* @buf: The write buffer
* @len: Length of the write buffer
*
* Writes a block of byte data from buf using the underlaying transport
* protocol. It returns the amount of bytes written or a negative error code.
*/
static inline int rmi_write_block(struct rmi_device *d, u16 addr,
const void *buf, size_t len)
{
return d->xport->ops->write_block(d->xport, addr, buf, len);
}
int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data));
extern struct bus_type rmi_bus_type;
int rmi_of_property_read_u32(struct device *dev, u32 *result,
const char *prop, bool optional);
#define RMI_DEBUG_CORE BIT(0)
#define RMI_DEBUG_XPORT BIT(1)
#define RMI_DEBUG_FN BIT(2)
#define RMI_DEBUG_2D_SENSOR BIT(3)
void rmi_dbg(int flags, struct device *dev, const char *fmt, ...);
#endif
此差异已折叠。
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#ifndef _RMI_DRIVER_H
#define _RMI_DRIVER_H
#include <linux/ctype.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/input.h>
#include "rmi_bus.h"
#define RMI_DRIVER_VERSION "2.0"
#define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
#define SYNAPTICS_VENDOR_ID 0x06cb
#define GROUP(_attrs) { \
.attrs = _attrs, \
}
#define PDT_PROPERTIES_LOCATION 0x00EF
#define BSR_LOCATION 0x00FE
#define RMI_PDT_PROPS_HAS_BSR 0x02
#define NAME_BUFFER_SIZE 256
#define RMI_PDT_ENTRY_SIZE 6
#define RMI_PDT_FUNCTION_VERSION_MASK 0x60
#define RMI_PDT_INT_SOURCE_COUNT_MASK 0x07
#define PDT_START_SCAN_LOCATION 0x00e9
#define PDT_END_SCAN_LOCATION 0x0005
#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
struct pdt_entry {
u16 page_start;
u8 query_base_addr;
u8 command_base_addr;
u8 control_base_addr;
u8 data_base_addr;
u8 interrupt_source_count;
u8 function_version;
u8 function_number;
};
int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
u16 pdt_address);
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
/* describes a single packet register */
struct rmi_register_desc_item {
u16 reg;
unsigned long reg_size;
u8 num_subpackets;
unsigned long subpacket_map[BITS_TO_LONGS(
RMI_REG_DESC_SUBPACKET_BITS)];
};
/*
* describes the packet registers for a particular type
* (ie query, control, data)
*/
struct rmi_register_descriptor {
unsigned long struct_size;
unsigned long presense_map[BITS_TO_LONGS(RMI_REG_DESC_PRESENSE_BITS)];
u8 num_registers;
struct rmi_register_desc_item *registers;
};
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
struct rmi_register_descriptor *rdesc);
const struct rmi_register_desc_item *rmi_get_register_desc_item(
struct rmi_register_descriptor *rdesc, u16 reg);
/*
* Calculate the total size of all of the registers described in the
* descriptor.
*/
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc);
int rmi_register_desc_calc_reg_offset(
struct rmi_register_descriptor *rdesc, u16 reg);
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket);
bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
char *rmi_f01_get_product_ID(struct rmi_function *fn);
extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler;
#endif
此差异已折叠。
此差异已折叠。
/*
* Copyright (c) 2012-2016 Synaptics Incorporated
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*/
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#include "rmi_2d_sensor.h"
enum rmi_f12_object_type {
RMI_F12_OBJECT_NONE = 0x00,
RMI_F12_OBJECT_FINGER = 0x01,
RMI_F12_OBJECT_STYLUS = 0x02,
RMI_F12_OBJECT_PALM = 0x03,
RMI_F12_OBJECT_UNCLASSIFIED = 0x04,
RMI_F12_OBJECT_GLOVED_FINGER = 0x06,
RMI_F12_OBJECT_NARROW_OBJECT = 0x07,
RMI_F12_OBJECT_HAND_EDGE = 0x08,
RMI_F12_OBJECT_COVER = 0x0A,
RMI_F12_OBJECT_STYLUS_2 = 0x0B,
RMI_F12_OBJECT_ERASER = 0x0C,
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
};
struct f12_data {
struct rmi_function *fn;
struct rmi_2d_sensor sensor;
struct rmi_2d_sensor_platform_data sensor_pdata;
u16 data_addr;
struct rmi_register_descriptor query_reg_desc;
struct rmi_register_descriptor control_reg_desc;
struct rmi_register_descriptor data_reg_desc;
/* F12 Data1 describes sensed objects */
const struct rmi_register_desc_item *data1;
u16 data1_offset;
/* F12 Data5 describes finger ACM */
const struct rmi_register_desc_item *data5;
u16 data5_offset;
/* F12 Data5 describes Pen */
const struct rmi_register_desc_item *data6;
u16 data6_offset;
/* F12 Data9 reports relative data */
const struct rmi_register_desc_item *data9;
u16 data9_offset;
const struct rmi_register_desc_item *data15;
u16 data15_offset;
};
static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
{
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor = &f12->sensor;
struct rmi_function *fn = sensor->fn;
struct rmi_device *rmi_dev = fn->rmi_dev;
int ret;
int offset;
u8 buf[14];
int pitch_x = 0;
int pitch_y = 0;
int clip_x_low = 0;
int clip_x_high = 0;
int clip_y_low = 0;
int clip_y_high = 0;
int rx_receivers = 0;
int tx_receivers = 0;
int sensor_flags = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) {
dev_err(&fn->dev,
"F12 does not have the sensor tuning control register\n");
return -ENODEV;
}
offset = rmi_register_desc_calc_reg_offset(&f12->control_reg_desc, 8);
if (item->reg_size > 14) {
dev_err(&fn->dev, "F12 control8 should be 14 bytes, not: %ld\n",
item->reg_size);
return -ENODEV;
}
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset, buf,
item->reg_size);
if (ret)
return ret;
offset = 0;
if (rmi_register_desc_has_subpacket(item, 0)) {
sensor->max_x = (buf[offset + 1] << 8) | buf[offset];
sensor->max_y = (buf[offset + 3] << 8) | buf[offset + 2];
offset += 4;
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: max_x: %d max_y: %d\n", __func__,
sensor->max_x, sensor->max_y);
if (rmi_register_desc_has_subpacket(item, 1)) {
pitch_x = (buf[offset + 1] << 8) | buf[offset];
pitch_y = (buf[offset + 3] << 8) | buf[offset + 2];
offset += 4;
}
if (rmi_register_desc_has_subpacket(item, 2)) {
sensor->axis_align.clip_x_low = buf[offset];
sensor->axis_align.clip_x_high = sensor->max_x
- buf[offset + 1];
sensor->axis_align.clip_y_low = buf[offset + 2];
sensor->axis_align.clip_y_high = sensor->max_y
- buf[offset + 3];
offset += 4;
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
__func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset];
tx_receivers = buf[offset + 1];
offset += 2;
}
if (rmi_register_desc_has_subpacket(item, 4)) {
sensor_flags = buf[offset];
offset += 1;
}
sensor->x_mm = (pitch_x * rx_receivers) >> 12;
sensor->y_mm = (pitch_y * tx_receivers) >> 12;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__,
sensor->x_mm, sensor->y_mm);
return 0;
}
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
{
int i;
struct rmi_2d_sensor *sensor = &f12->sensor;
for (i = 0; i < f12->data1->num_subpackets; i++) {
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
obj->type = RMI_2D_OBJECT_NONE;
obj->mt_tool = MT_TOOL_FINGER;
switch (data1[0]) {
case RMI_F12_OBJECT_FINGER:
obj->type = RMI_2D_OBJECT_FINGER;
break;
case RMI_F12_OBJECT_STYLUS:
obj->type = RMI_2D_OBJECT_STYLUS;
obj->mt_tool = MT_TOOL_PEN;
break;
case RMI_F12_OBJECT_PALM:
obj->type = RMI_2D_OBJECT_PALM;
obj->mt_tool = MT_TOOL_PALM;
break;
case RMI_F12_OBJECT_UNCLASSIFIED:
obj->type = RMI_2D_OBJECT_UNCLASSIFIED;
break;
}
obj->x = (data1[2] << 8) | data1[1];
obj->y = (data1[4] << 8) | data1[3];
obj->z = data1[5];
obj->wx = data1[6];
obj->wy = data1[7];
rmi_2d_sensor_abs_process(sensor, obj, i);
data1 += 8;
}
if (sensor->kernel_tracking)
input_mt_assign_slots(sensor->input,
sensor->tracking_slots,
sensor->tracking_pos,
sensor->nbr_fingers,
sensor->dmax);
for (i = 0; i < sensor->nbr_fingers; i++)
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
}
static int rmi_f12_attention(struct rmi_function *fn,
unsigned long *irq_nr_regs)
{
int retval;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
struct rmi_2d_sensor *sensor = &f12->sensor;
if (rmi_dev->xport->attn_data) {
memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
sensor->attn_size);
rmi_dev->xport->attn_data += sensor->attn_size;
rmi_dev->xport->attn_size -= sensor->attn_size;
} else {
retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size);
if (retval < 0) {
dev_err(&fn->dev, "Failed to read object data. Code: %d.\n",
retval);
return retval;
}
}
if (f12->data1)
rmi_f12_process_objects(f12,
&sensor->data_pkt[f12->data1_offset]);
input_mt_sync_frame(sensor->input);
return 0;
}
static int rmi_f12_config(struct rmi_function *fn)
{
struct rmi_driver *drv = fn->rmi_dev->driver;
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
return 0;
}
static int rmi_f12_probe(struct rmi_function *fn)
{
struct f12_data *f12;
int ret;
struct rmi_device *rmi_dev = fn->rmi_dev;
char buf;
u16 query_addr = fn->fd.query_base_addr;
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor;
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
struct rmi_transport_dev *xport = rmi_dev->xport;
u16 data_offset = 0;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
ret = rmi_read(fn->rmi_dev, query_addr, &buf);
if (ret < 0) {
dev_err(&fn->dev, "Failed to read general info register: %d\n",
ret);
return -ENODEV;
}
++query_addr;
if (!(buf & 0x1)) {
dev_err(&fn->dev,
"Behavior of F12 without register descriptors is undefined.\n");
return -ENODEV;
}
f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data), GFP_KERNEL);
if (!f12)
return -ENOMEM;
if (fn->dev.of_node) {
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
if (ret)
return ret;
} else if (pdata->sensor_pdata) {
f12->sensor_pdata = *pdata->sensor_pdata;
}
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->query_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Query Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->control_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Control Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->data_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Data Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
sensor = &f12->sensor;
sensor->fn = fn;
f12->data_addr = fn->fd.data_base_addr;
sensor->pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc);
sensor->axis_align =
f12->sensor_pdata.axis_align;
sensor->x_mm = f12->sensor_pdata.x_mm;
sensor->y_mm = f12->sensor_pdata.y_mm;
if (sensor->sensor_type == rmi_sensor_default)
sensor->sensor_type =
f12->sensor_pdata.sensor_type;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %d\n", __func__,
sensor->pkt_size);
sensor->data_pkt = devm_kzalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL);
if (!sensor->data_pkt)
return -ENOMEM;
dev_set_drvdata(&fn->dev, f12);
ret = rmi_f12_read_sensor_tuning(f12);
if (ret)
return ret;
/*
* Figure out what data is contained in the data registers. HID devices
* may have registers defined, but their data is not reported in the
* HID attention report. Registers which are not reported in the HID
* attention report check to see if the device is receiving data from
* HID attention reports.
*/
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
if (item) {
f12->data1 = item;
f12->data1_offset = data_offset;
data_offset += item->reg_size;
sensor->nbr_fingers = item->num_subpackets;
sensor->report_abs = 1;
sensor->attn_size += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
if (item) {
f12->data5 = item;
f12->data5_offset = data_offset;
data_offset += item->reg_size;
sensor->attn_size += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
if (item && !xport->attn_data) {
f12->data6 = item;
f12->data6_offset = data_offset;
data_offset += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
if (item && !xport->attn_data) {
f12->data9 = item;
f12->data9_offset = data_offset;
data_offset += item->reg_size;
if (!sensor->report_abs)
sensor->report_rel = 1;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
if (item && !xport->attn_data) {
f12->data15 = item;
f12->data15_offset = data_offset;
data_offset += item->reg_size;
}
/* allocate the in-kernel tracking buffers */
sensor->tracking_pos = devm_kzalloc(&fn->dev,
sizeof(struct input_mt_pos) * sensor->nbr_fingers,
GFP_KERNEL);
sensor->tracking_slots = devm_kzalloc(&fn->dev,
sizeof(int) * sensor->nbr_fingers, GFP_KERNEL);
sensor->objs = devm_kzalloc(&fn->dev,
sizeof(struct rmi_2d_sensor_abs_object)
* sensor->nbr_fingers, GFP_KERNEL);
if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs)
return -ENOMEM;
ret = rmi_2d_sensor_configure_input(fn, sensor);
if (ret)
return ret;
return 0;
}
struct rmi_function_handler rmi_f12_handler = {
.driver = {
.name = "rmi4_f12",
},
.func = 0x12,
.probe = rmi_f12_probe,
.config = rmi_f12_config,
.attention = rmi_f12_attention,
};
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -334,7 +334,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_GOODIX
tristate "Goodix I2C touchscreen"
depends on I2C
depends on GPIOLIB
depends on GPIOLIB || COMPILE_TEST
help
Say Y here if you have the Goodix touchscreen (such as one
installed in Onda v975w tablets) connected to your
......@@ -491,6 +491,17 @@ config TOUCHSCREEN_MMS114
To compile this driver as a module, choose M here: the
module will be called mms114.
config TOUCHSCREEN_MELFAS_MIP4
tristate "MELFAS MIP4 Touchscreen"
depends on I2C
help
Say Y here if you have a MELFAS MIP4 Touchscreen device.
If unsure, say N.
To compile this driver as a module, choose M here:
the module will be called melfas_mip4.
config TOUCHSCREEN_MTOUCH
tristate "MicroTouch serial touchscreens"
select SERIO
......@@ -941,6 +952,7 @@ config TOUCHSCREEN_TOUCHIT213
config TOUCHSCREEN_TS4800
tristate "TS-4800 touchscreen"
depends on HAS_IOMEM && OF
depends on SOC_IMX51 || COMPILE_TEST
select MFD_SYSCON
select INPUT_POLLDEV
help
......@@ -1112,7 +1124,8 @@ config TOUCHSCREEN_ZFORCE
config TOUCHSCREEN_COLIBRI_VF50
tristate "Toradex Colibri on board touchscreen driver"
depends on GPIOLIB && IIO && VF610_ADC
depends on IIO && VF610_ADC
depends on GPIOLIB || COMPILE_TEST
help
Say Y here if you have a Colibri VF50 and plan to use
the on-board provided 4-wire touchscreen driver.
......
......@@ -48,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.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_MTOUCH) += mtouch.o
......
......@@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/pm.h>
#include "ad7879.h"
......@@ -91,10 +92,19 @@ static const struct i2c_device_id ad7879_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ad7879_id);
#ifdef CONFIG_OF
static const struct of_device_id ad7879_i2c_dt_ids[] = {
{ .compatible = "adi,ad7879-1", },
{ }
};
MODULE_DEVICE_TABLE(of, ad7879_i2c_dt_ids);
#endif
static struct i2c_driver ad7879_i2c_driver = {
.driver = {
.name = "ad7879",
.pm = &ad7879_pm_ops,
.of_match_table = of_match_ptr(ad7879_i2c_dt_ids),
},
.probe = ad7879_i2c_probe,
.remove = ad7879_i2c_remove,
......
......@@ -10,6 +10,7 @@
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/of.h>
#include "ad7879.h"
......@@ -146,10 +147,19 @@ static int ad7879_spi_remove(struct spi_device *spi)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id ad7879_spi_dt_ids[] = {
{ .compatible = "adi,ad7879", },
{ }
};
MODULE_DEVICE_TABLE(of, ad7879_spi_dt_ids);
#endif
static struct spi_driver ad7879_spi_driver = {
.driver = {
.name = "ad7879",
.pm = &ad7879_pm_ops,
.of_match_table = of_match_ptr(ad7879_spi_dt_ids),
},
.probe = ad7879_spi_probe,
.remove = ad7879_spi_remove,
......
此差异已折叠。
......@@ -129,7 +129,6 @@ struct cyttsp {
int irq;
struct input_dev *input;
char phys[32];
const struct cyttsp_platform_data *pdata;
const struct cyttsp_bus_ops *bus_ops;
struct cyttsp_bootloader_data bl_data;
struct cyttsp_sysinfo_data sysinfo_data;
......@@ -138,12 +137,19 @@ struct cyttsp {
enum cyttsp_state state;
bool suspended;
struct gpio_desc *reset_gpio;
bool use_hndshk;
u8 act_dist;
u8 act_intrvl;
u8 tch_tmout;
u8 lp_intrvl;
u8 *bl_keys;
u8 xfer_buf[] ____cacheline_aligned;
};
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size);
void cyttsp_remove(struct cyttsp *ts);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
u8 length, const void *values);
......
......@@ -56,15 +56,6 @@ static int cyttsp_i2c_probe(struct i2c_client *client,
return 0;
}
static int cyttsp_i2c_remove(struct i2c_client *client)
{
struct cyttsp *ts = i2c_get_clientdata(client);
cyttsp_remove(ts);
return 0;
}
static const struct i2c_device_id cyttsp_i2c_id[] = {
{ CY_I2C_NAME, 0 },
{ }
......@@ -77,7 +68,6 @@ static struct i2c_driver cyttsp_i2c_driver = {
.pm = &cyttsp_pm_ops,
},
.probe = cyttsp_i2c_probe,
.remove = cyttsp_i2c_remove,
.id_table = cyttsp_i2c_id,
};
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册