* [RESEND PATCH V7 0/3] da7280: haptic driver submission
From: Roy Im @ 2018-10-17 0:57 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring
Cc: Mark Rutland, Support Opensource, devicetree, linux-input,
linux-kernel
This patch adds support for the Dialog DA7280 Haptic driver IC.
In this patch set the following is provided:
[PATCH V7 1/3] MAINTAINERS file update for DA7280
[PATCH V7 2/3] DA7280 DT Binding
[PATCH V7 3/3] DA7280 Driver
This patch applies against linux-next and v4.19-rc6
Thank you,
Roy Im, Dialog Semiconductor Ltd.
Roy Im (3):
MAINTAINERS: da7280 updates to the Dialog Semiconductor search terms
dt-bindings: input: Add document bindings for DA7280
Input: new da7280 haptic driver
.../devicetree/bindings/input/dlg,da7280.txt | 105 ++
MAINTAINERS | 2 +
drivers/input/misc/Kconfig | 13 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/da7280.c | 1409 ++++++++++++++++++++
drivers/input/misc/da7280.h | 412 ++++++
6 files changed, 1942 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/dlg,da7280.txt
create mode 100644 drivers/input/misc/da7280.c
create mode 100644 drivers/input/misc/da7280.h
--
end-of-patch for RESEND PATCH V7
^ permalink raw reply
* [RESEND PATCH V7 2/3] dt-bindings: input: Add document bindings for DA7280
From: Roy Im @ 2018-10-17 0:57 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring
Cc: Mark Rutland, Support Opensource, devicetree, linux-input,
linux-kernel
In-Reply-To: <cover.1539737877.git.Roy.Im@diasemi.com>
Add device tree binding information for DA7280 haptic driver.
Example bindings for DA7280 are added.
Reviewed-by: Rob Herring <robh@kernel.org>.
Signed-off-by: Roy Im <roy.im.opensource@diasemi.com>
---
v7: No changes.
v6: No changes.
v5: Updated descriptions and fixed errors.
v4: Fixed commit message, properties.
v3: Fixed subject format.
v2: No changes
.../devicetree/bindings/input/dlg,da7280.txt | 105 ++++++++++++++++++++
1 file changed, 105 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/dlg,da7280.txt
diff --git a/Documentation/devicetree/bindings/input/dlg,da7280.txt b/Documentation/devicetree/bindings/input/dlg,da7280.txt
new file mode 100644
index 0000000..a25a12f
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/dlg,da7280.txt
@@ -0,0 +1,105 @@
+Dialog Semiconductor DA7280 Haptics bindings
+
+Required properties:
+- compatible: Should be "dlg,da7280".
+- reg: Specifies the I2C slave address.
+
+- interrupt-parent : Specifies the phandle of the interrupt controller to
+ which the IRQs from DA7280 are delivered to.
+
+- dlg,actuator-type: Set Actuator type. it should be one of:
+ "LRA" - Linear Resonance Actuator type.
+ "ERM-bar" - Bar type Eccentric Rotating Mass.
+ "ERM-coin" - Coin type Eccentric Rotating Mass.
+
+- dlg,op-mode: Haptic operation mode.
+ Possible values:
+ 1 - Direct register override(DRO) mode triggered by i2c(default),
+ 2 - PWM data source mode controlled by PWM duty,
+ 3 - Register triggered waveform memory(RTWM) mode, the pattern
+ assigned to the PS_SEQ_ID played as much times as PS_SEQ_LOOP,
+ 4 - Edge triggered waveform memory(ETWM) mode, external GPI(N)
+ control are required to enable/disable and it needs to keep
+ device enabled by sending magnitude (X > 0),
+ the pattern is assigned to the GPI(N)_SEQUENCE_ID below.
+ For more details, please see the datasheet.
+
+- dlg,nom-microvolt: Nominal actuator voltage rating.
+ Valid values: 0 - 6000000.
+- dlg,abs-max-microvolt: Absolute actuator maximum voltage rating.
+ Valid values: 0 - 6000000.
+- dlg,imax-microamp: Actuator max current rating.
+ Valid values: 0 - 252000.
+ Default: 130000.
+- dlg,impd-micro-ohms: the impedance of the actuator in micro ohms.
+ Valid values: 0 - 1500000000.
+
+Optional properties:
+- pwms : phandle to the physical PWM(Pulse Width Modulation) device.
+ PWM properties should be named "pwms". And number of cell is different
+ for each pwm device.
+ (See Documentation/devicetree/bindings/pwm/pwm.txt
+ for further information relating to pwm properties)
+
+- dlg,ps-seq-id: the PS_SEQ_ID(pattern ID in waveform memory inside chip)
+ to play back when RTWM-MODE is enabled.
+ Valid range: 0 - 15.
+- dlg,ps-seq-loop: the PS_SEQ_LOOP, Number of times the pre-stored sequence
+ pointed to by PS_SEQ_ID or GPI(N)_SEQUENCE_ID is repeated.
+ Valid range: 0 - 15.
+- dlg,gpiN-seq-id: the GPI(N)_SEQUENCE_ID, pattern to play
+ when gpi0 is triggered, 'N' must be 0 - 2.
+ Valid range: 0 - 15.
+- dlg,gpiN-mode: the pattern mode which can select either
+ "Single-pattern" or "Multi-pattern", 'N' must be 0 - 2.
+- dlg,gpiN-polarity: gpiN polarity which can be chosen among
+ "Rising-edge", "Falling-edge" and "Both-edge",
+ 'N' must be 0 - 2
+ Haptic will work by this edge option in case of ETWM mode.
+
+- dlg,resonant-freq-hz: use in case of LRA.
+ the frequency range: 50 - 300.
+ Default: 205.
+
+- dlg,bemf-sens-enable: Enable for internal loop computations.
+- dlg,freq-track-enable: Enable for resonant frequency tracking.
+- dlg,acc-enable: Enable for active acceleration.
+- dlg,rapid-stop-enable: Enable for rapid stop.
+- dlg,amp-pid-enable: Enable for the amplitude PID.
+- dlg,mem-array: Customized waveform memory(patterns) data downloaded to
+ the device during initialization. This is an array of 100 values(u8).
+
+For further information, see device datasheet.
+
+======
+
+Example:
+
+ haptics: da7280-haptics@4a {
+ compatible = "dlg,da7280";
+ reg = <0x4a>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+ dlg,actuator-type = "LRA";
+ dlg,op-mode = <1>;
+ dlg,nom-microvolt = <2000000>;
+ dlg,abs-max-microvolt = <2000000>;
+ dlg,imax-microamp = <170000>;
+ dlg,resonant-freq-hz = <180>;
+ dlg,impd-micro-ohms = <10500000>;
+ dlg,freq-track-enable;
+ dlg,rapid-stop-enable;
+ dlg,mem-array = <
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
+ >;
+
+ };
--
end-of-patch for RESEND PATCH V7
^ permalink raw reply related
* [RESEND PATCH V7 3/3] Input: new da7280 haptic driver
From: Roy Im @ 2018-10-17 0:57 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring
Cc: Mark Rutland, Support Opensource, devicetree, linux-input,
linux-kernel
In-Reply-To: <cover.1539737877.git.Roy.Im@diasemi.com>
Adds support for the Dialog DA7280 LRA/ERM Haptic Driver with
multiple mode and integrated waveform memory and wideband support.
It communicates via an I2C bus to the device.
Signed-off-by: Roy Im <roy.im.opensource@diasemi.com>
---
v7:
- Added more attributes to handle one value per file.
- Replaced and updated the dt-related code and functions called.
- Fixed error/functions.
- Rebased to v4.19-rc6.
v6: No changes.
v5: Fixed errors in Kconfig file.
v4: Updated code as dt-bindings are changed.
v3: No changes.
v2: Fixed kbuild error/warning
drivers/input/misc/Kconfig | 13 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/da7280.c | 1409 +++++++++++++++++++++++++++++++++++++++++++
drivers/input/misc/da7280.h | 412 +++++++++++++
4 files changed, 1835 insertions(+)
create mode 100644 drivers/input/misc/da7280.c
create mode 100644 drivers/input/misc/da7280.h
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index ca59a2b..751cac6 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -851,4 +851,17 @@ config INPUT_SC27XX_VIBRA
To compile this driver as a module, choose M here. The module will
be called sc27xx_vibra.
+config INPUT_DA7280_HAPTICS
+ tristate "Dialog Semiconductor DA7280 haptics support"
+ depends on INPUT && I2C
+ select INPUT_FF_MEMLESS
+ select REGMAP_I2C
+ help
+ Say Y to enable support for the Dialog DA7280 haptics driver.
+ The haptics can be controlled by i2c communication,
+ or by PWM input, or by GPI.
+
+ To compile this driver as a module, choose M here: the
+ module will be called da7280.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 9d0f9d1..d941348 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o
+obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
new file mode 100644
index 0000000..b1072ef
--- /dev/null
+++ b/drivers/input/misc/da7280.c
@@ -0,0 +1,1409 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * DA7280 Haptic device driver
+ *
+ * Copyright (c) 2018 Dialog Semiconductor.
+ * Author: Roy Im <Roy.Im.Opensource@diasemi.com>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+#include "da7280.h"
+
+/* uV unit for voltage rate */
+#define DA7280_VOLTAGE_RATE_MAX 6000000
+#define DA7280_VOLTAGE_RATE_STEP 23400
+#define DA7280_NOMMAX_DFT 0x6B
+#define DA7280_ABSMAX_DFT 0x78
+
+#define DA7280_IMPD_MAX 1500000000
+#define DA7280_IMPD_DEFAULT 22000000
+
+#define DA7280_IMAX_DEFAULT 0x0E
+/* uA unit step and limit for IMAX*/
+#define DA7280_IMAX_STEP 7200
+#define DA7280_IMAX_LIMIT 252000
+
+#define DA7280_RESONT_FREQH_DFT 0x39
+#define DA7280_RESONT_FREQL_DFT 0x32
+#define DA7280_MIN_RESONAT_FREQ_HZ 50
+#define DA7280_MAX_RESONAT_FREQ_HZ 300
+#define DA7280_MIN_PWM_FREQ_KHZ 10
+#define DA7280_MAX_PWM_FREQ_KHZ 250
+
+#define DA7280_SEQ_ID_MAX 15
+#define DA7280_SEQ_LOOP_MAX 15
+#define DA7280_GPI1_SEQ_ID_DEFT 0x0
+
+#define DA7280_SNP_MEM_SIZE 100
+#define DA7280_SNP_MEM_MAX DA7280_SNP_MEM_99
+
+#define IRQ_NUM 3
+
+#define DA7280_SKIP_INIT 0x100
+
+enum da7280_haptic_dev_t {
+ DA7280_LRA = 0,
+ DA7280_ERM_BAR = 1,
+ DA7280_ERM_COIN = 2,
+ DA7280_DEV_MAX,
+};
+
+enum da7280_op_mode {
+ DA7280_INACTIVE = 0,
+ DA7280_DRO_MODE = 1,
+ DA7280_PWM_MODE = 2,
+ DA7280_RTWM_MODE = 3,
+ DA7280_ETWM_MODE = 4,
+ DA7280_OPMODE_MAX,
+};
+
+struct da7280_gpi_ctl {
+ u8 seq_id;
+ u8 mode;
+ u8 polarity;
+};
+
+struct da7280_haptic {
+ struct regmap *regmap;
+ struct input_dev *input_dev;
+ struct device *dev;
+ struct i2c_client *client;
+ struct pwm_device *pwm_dev;
+ bool legacy;
+ int pwm_id;
+ struct work_struct work;
+
+ unsigned int magnitude;
+
+ u8 dev_type;
+ u8 op_mode;
+ u16 nommax;
+ u16 absmax;
+ u32 imax;
+ u32 impd;
+ u32 resonant_freq_h;
+ u32 resonant_freq_l;
+ bool bemf_sense_en;
+ bool freq_track_en;
+ bool acc_en;
+ bool rapid_stop_en;
+ bool amp_pid_en;
+ u8 ps_seq_id;
+ u8 ps_seq_loop;
+ struct da7280_gpi_ctl gpi_ctl[3];
+ bool mem_update;
+ u8 snp_mem[DA7280_SNP_MEM_SIZE];
+ u8 enabled;
+};
+
+static bool da7280_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA7280_IRQ_EVENT1:
+ case DA7280_IRQ_EVENT_WARNING_DIAG:
+ case DA7280_IRQ_EVENT_SEQ_DIAG:
+ case DA7280_IRQ_STATUS1:
+ case DA7280_TOP_CTL1:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config da7280_haptic_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = DA7280_SNP_MEM_MAX,
+ .volatile_reg = da7280_volatile_register,
+};
+
+static int da7280_haptic_mem_update(struct da7280_haptic *haptics)
+{
+ int error;
+ unsigned int val;
+
+ /* It is recommended to update the patterns
+ * during haptic is not working in order to avoid conflict
+ */
+ error = regmap_read(haptics->regmap, DA7280_IRQ_STATUS1, &val);
+ if (error)
+ return error;
+ if (val & DA7280_STA_WARNING_MASK) {
+ dev_warn(haptics->dev,
+ "Warning! Please check HAPTIC status.\n");
+ return -EBUSY;
+ }
+
+ /* Patterns are not updated if the lock bit is enabled */
+ val = 0;
+ error = regmap_read(haptics->regmap, DA7280_MEM_CTL2, &val);
+ if (error)
+ return error;
+ if (~val & DA7280_WAV_MEM_LOCK_MASK) {
+ dev_warn(haptics->dev,
+ "Please unlock the bit first\n");
+ return -EACCES;
+ }
+
+ /* Set to Inactive mode to make sure safety */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK,
+ 0);
+ if (error)
+ return error;
+
+ error = regmap_read(haptics->regmap, DA7280_MEM_CTL1, &val);
+ if (error)
+ return error;
+
+ return regmap_bulk_write(haptics->regmap, val,
+ haptics->snp_mem, DA7280_SNP_MEM_MAX - val + 1);
+}
+
+static int da7280_haptic_set_pwm(struct da7280_haptic *haptics)
+{
+ struct pwm_args pargs;
+ u64 period_mag_multi;
+ unsigned int pwm_duty;
+ int error;
+
+ pwm_get_args(haptics->pwm_dev, &pargs);
+ period_mag_multi =
+ (u64)(pargs.period * haptics->magnitude);
+ if (haptics->acc_en)
+ pwm_duty =
+ (unsigned int)(period_mag_multi >> 16);
+ else
+ pwm_duty =
+ (unsigned int)((period_mag_multi >> 16)
+ + pargs.period) / 2;
+
+ error = pwm_config(haptics->pwm_dev,
+ pwm_duty, pargs.period);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to configure pwm : %d\n", error);
+ return error;
+ }
+
+ error = pwm_enable(haptics->pwm_dev);
+ if (error) {
+ pwm_disable(haptics->pwm_dev);
+ dev_err(haptics->dev,
+ "failed to enable haptics pwm device : %d\n", error);
+ }
+
+ return error;
+}
+
+static void da7280_haptic_enable(struct da7280_haptic *haptics)
+{
+ int error = 0;
+
+ if (haptics->enabled)
+ return;
+
+ switch (haptics->op_mode) {
+ case DA7280_DRO_MODE:
+ /* the valid range check when acc_en is enabled */
+ if (haptics->acc_en && haptics->magnitude > 0x7F)
+ haptics->magnitude = 0x7F;
+ else if (haptics->magnitude > 0xFF)
+ haptics->magnitude = 0xFF;
+
+ /* Set driver level
+ * as a % of ACTUATOR_NOMMAX(nommax)
+ */
+ error = regmap_write(haptics->regmap,
+ DA7280_TOP_CTL2,
+ haptics->magnitude);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for driving level set : %d\n",
+ error);
+ return;
+ }
+ break;
+ case DA7280_PWM_MODE:
+ if (da7280_haptic_set_pwm(haptics))
+ return;
+ break;
+ case DA7280_RTWM_MODE:
+ /* PS_SEQ_ID will be played
+ * as many times as the PS_SEQ_LOOP
+ */
+ case DA7280_ETWM_MODE:
+ /* Now users are able to control the GPI(N)
+ * assigned to GPI_0, GPI1 and GPI2 accordingly
+ * please see the datasheet for details.
+ * GPI(N)_SEQUENCE_ID will be played
+ * as many times as the PS_SEQ_LOOP
+ */
+ break;
+ default:
+ dev_err(haptics->dev,
+ "Invalid Mode(%d)\n", haptics->op_mode);
+ return;
+ }
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK,
+ haptics->op_mode);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for op_mode setting : %d\n", error);
+ return;
+ }
+
+ if (haptics->op_mode == DA7280_PWM_MODE ||
+ haptics->op_mode == DA7280_RTWM_MODE) {
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_SEQ_START_MASK,
+ DA7280_SEQ_START_MASK);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for sequence triggering : %d\n",
+ error);
+ return;
+ }
+ }
+
+ haptics->enabled = true;
+}
+
+static void da7280_haptic_disable(struct da7280_haptic *haptics)
+{
+ int error;
+
+ if (!haptics->enabled)
+ return;
+
+ /* Set to Inactive mode */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for op_mode off : %d\n", error);
+ return;
+ }
+
+ switch (haptics->op_mode) {
+ case DA7280_RTWM_MODE:
+ case DA7280_ETWM_MODE:
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_SEQ_START_MASK, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for RTWM or ETWM mode off : %d\n",
+ error);
+ return;
+ }
+ break;
+ case DA7280_DRO_MODE:
+ error = regmap_write(haptics->regmap,
+ DA7280_TOP_CTL2, 0);
+ if (error) {
+ dev_err(haptics->dev,
+ "i2c err for DRO mode off : %d\n",
+ error);
+ return;
+ }
+ break;
+ case DA7280_PWM_MODE:
+ pwm_disable(haptics->pwm_dev);
+ break;
+ default:
+ dev_err(haptics->dev,
+ "Invalid Mode(%d)\n", haptics->op_mode);
+ break;
+ }
+
+ if (haptics->op_mode < DA7280_OPMODE_MAX)
+ haptics->enabled = false;
+}
+
+static void da7280_haptic_work(struct work_struct *work)
+{
+ struct da7280_haptic *haptics =
+ container_of(work, struct da7280_haptic, work);
+
+ if (haptics->magnitude)
+ da7280_haptic_enable(haptics);
+ else
+ da7280_haptic_disable(haptics);
+}
+
+static int da7280_haptic_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+
+ if (effect->u.rumble.strong_magnitude > 0)
+ haptics->magnitude = effect->u.rumble.strong_magnitude;
+ else if (effect->u.rumble.weak_magnitude > 0)
+ haptics->magnitude = effect->u.rumble.weak_magnitude;
+ else
+ haptics->magnitude = 0;
+
+ schedule_work(&haptics->work);
+
+ return 0;
+}
+
+static int da7280_haptic_open(struct input_dev *dev)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+ int error;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK,
+ DA7280_STANDBY_EN_MASK);
+ if (error)
+ dev_err(haptics->dev,
+ "Failed to open haptic, i2c error : %d\n", error);
+
+ return error;
+}
+
+static void da7280_haptic_close(struct input_dev *dev)
+{
+ struct da7280_haptic *haptics = input_get_drvdata(dev);
+ int error;
+
+ cancel_work_sync(&haptics->work);
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK, 0);
+ if (error)
+ goto error_i2c;
+
+ if (haptics->op_mode == DA7280_DRO_MODE) {
+ error = regmap_write(haptics->regmap,
+ DA7280_TOP_CTL2, 0);
+
+ if (error)
+ goto error_i2c;
+ }
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK, 0);
+ if (error)
+ goto error_i2c;
+
+ return;
+
+error_i2c:
+ dev_err(haptics->dev, "DA7280-haptic i2c error : %d\n", error);
+}
+
+static u8 da7280_haptic_of_mode_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "LRA"))
+ return DA7280_LRA;
+ else if (!strcmp(str, "ERM-bar"))
+ return DA7280_ERM_BAR;
+ else if (!strcmp(str, "ERM-coin"))
+ return DA7280_ERM_COIN;
+
+ dev_warn(dev, "Invalid string - set to default\n");
+ return DA7280_LRA;
+}
+
+static u8 da7280_haptic_of_gpi_mode_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "Single-pattern"))
+ return 0;
+ else if (!strcmp(str, "Multi-pattern"))
+ return 1;
+
+ dev_warn(dev, "Invalid string - set to default\n");
+ return 0;
+}
+
+static u8 da7280_haptic_of_gpi_pol_str(struct device *dev,
+ const char *str)
+{
+ if (!strcmp(str, "Rising-edge"))
+ return 0;
+ else if (!strcmp(str, "Falling-edge"))
+ return 1;
+ else if (!strcmp(str, "Both-edge"))
+ return 2;
+
+ dev_warn(dev, "Invalid string - set to default\n");
+ return 0;
+}
+
+static u8 da7280_haptic_of_volt_rating_set(u32 val)
+{
+ u32 voltage;
+
+ voltage = val / DA7280_VOLTAGE_RATE_STEP + 1;
+
+ if (voltage > 0xFF)
+ return 0xFF;
+ return (u8)voltage;
+}
+
+static void da7280_parse_properties(struct device *dev,
+ struct da7280_haptic *haptics)
+{
+ char gpi_str1[] = "dlg,gpi0-seq-id";
+ char gpi_str2[] = "dlg,gpi0-mode";
+ char gpi_str3[] = "dlg,gpi0-polarity";
+ unsigned int i, mem[DA7280_SNP_MEM_SIZE];
+ const char *str;
+ u32 val;
+
+ if (!device_property_read_string(dev, "dlg,actuator-type", &str))
+ haptics->dev_type =
+ da7280_haptic_of_mode_str(dev, str);
+ else /* if no property, then use the mode inside chip */
+ haptics->dev_type = DA7280_DEV_MAX;
+
+ if (device_property_read_u32(dev, "dlg,op-mode", &val) >= 0)
+ if (val > 0 && val < DA7280_OPMODE_MAX)
+ haptics->op_mode = val;
+ else
+ haptics->op_mode = DA7280_DRO_MODE;
+ else
+ haptics->op_mode = DA7280_DRO_MODE;
+
+ if (device_property_read_u32(dev, "dlg,nom-microvolt", &val) >= 0)
+ if (val < DA7280_VOLTAGE_RATE_MAX)
+ haptics->nommax =
+ da7280_haptic_of_volt_rating_set(val);
+ else
+ haptics->nommax = DA7280_SKIP_INIT;
+ else /* if no property, then use the value inside chip */
+ haptics->nommax = DA7280_SKIP_INIT;
+
+ if (device_property_read_u32(dev, "dlg,abs-max-microvolt",
+ &val) >= 0)
+ if (val < DA7280_VOLTAGE_RATE_MAX)
+ haptics->absmax =
+ da7280_haptic_of_volt_rating_set(val);
+ else
+ haptics->absmax = DA7280_SKIP_INIT;
+ else
+ haptics->absmax = DA7280_SKIP_INIT;
+
+ if (device_property_read_u32(dev, "dlg,imax-microamp", &val) >= 0)
+ if (val < DA7280_IMAX_LIMIT)
+ haptics->imax = (val - 28600)
+ / DA7280_IMAX_STEP + 1;
+ else
+ haptics->imax = DA7280_IMAX_DEFAULT;
+ else
+ haptics->imax = DA7280_IMAX_DEFAULT;
+
+ if (device_property_read_u32(dev, "dlg,impd-micro-ohms", &val) >= 0)
+ if (val <= DA7280_IMPD_MAX)
+ haptics->impd = val;
+ else
+ haptics->impd = DA7280_IMPD_DEFAULT;
+ else
+ haptics->impd = DA7280_IMPD_DEFAULT;
+
+ if (device_property_read_u32(dev, "dlg,resonant-freq-hz",
+ &val) >= 0) {
+ if (val < DA7280_MAX_RESONAT_FREQ_HZ &&
+ val > DA7280_MIN_RESONAT_FREQ_HZ) {
+ haptics->resonant_freq_h =
+ ((1000000000 / (val * 1333)) >> 7) & 0xFF;
+ haptics->resonant_freq_l =
+ (1000000000 / (val * 1333)) & 0x7F;
+ } else {
+ haptics->resonant_freq_h =
+ DA7280_RESONT_FREQH_DFT;
+ haptics->resonant_freq_l =
+ DA7280_RESONT_FREQL_DFT;
+ }
+ } else {
+ haptics->resonant_freq_h = DA7280_SKIP_INIT;
+ haptics->resonant_freq_l = DA7280_SKIP_INIT;
+ }
+
+ if (device_property_read_u32(dev, "dlg,ps-seq-id", &val) >= 0)
+ if (val <= DA7280_SEQ_ID_MAX)
+ haptics->ps_seq_id = val;
+ else
+ haptics->ps_seq_id = 0;
+ else /* if no property, set to zero as a default do nothing */
+ haptics->ps_seq_id = 0;
+
+ if (device_property_read_u32(dev, "dlg,ps-seq-loop", &val) >= 0)
+ if (val <= DA7280_SEQ_LOOP_MAX)
+ haptics->ps_seq_loop = val;
+ else
+ haptics->ps_seq_loop = 0;
+ else /* if no property, then do nothing */
+ haptics->ps_seq_loop = 0;
+
+ /* GPI0~2 Control */
+ for (i = 0; i < 3; i++) {
+ gpi_str1[7] = '0' + i;
+ if (device_property_read_u32 (dev, gpi_str1, &val) >= 0)
+ if (val <= DA7280_SEQ_ID_MAX)
+ haptics->gpi_ctl[i].seq_id = val;
+ else
+ haptics->gpi_ctl[i].seq_id =
+ DA7280_GPI1_SEQ_ID_DEFT + i;
+ else /* if no property, then do nothing */
+ haptics->gpi_ctl[i].seq_id =
+ DA7280_GPI1_SEQ_ID_DEFT + i;
+
+ gpi_str2[7] = '0' + i;
+ if (!device_property_read_string(dev, gpi_str2, &str))
+ haptics->gpi_ctl[i].mode =
+ da7280_haptic_of_gpi_mode_str(dev, str);
+ else
+ haptics->gpi_ctl[i].mode = 0;
+
+ gpi_str3[7] = '0' + i;
+ if (!device_property_read_string(dev, gpi_str3, &str))
+ haptics->gpi_ctl[i].polarity =
+ da7280_haptic_of_gpi_pol_str(dev, str);
+ else
+ haptics->gpi_ctl[i].polarity = 0;
+ }
+
+ haptics->bemf_sense_en =
+ device_property_read_bool(dev, "dlg,bemf-sens-enable");
+ haptics->freq_track_en =
+ device_property_read_bool(dev, "dlg,freq-track-enable");
+ haptics->acc_en =
+ device_property_read_bool(dev, "dlg,acc-enable");
+ haptics->rapid_stop_en =
+ device_property_read_bool(dev, "dlg,rapid-stop-enable");
+ haptics->amp_pid_en =
+ device_property_read_bool(dev, "dlg,amp-pid-enable");
+
+ if (device_property_read_u32_array(dev, "dlg,mem-array",
+ &mem[0],
+ DA7280_SNP_MEM_SIZE) >= 0) {
+ haptics->mem_update = true;
+ for (i = 0; i < DA7280_SNP_MEM_SIZE; i++) {
+ if (mem[i] > 0xff)
+ haptics->snp_mem[i] = 0x0;
+ else
+ haptics->snp_mem[i] = (u8)mem[i];
+ }
+ } else {
+ haptics->mem_update = false;
+ }
+}
+
+static irqreturn_t da7280_irq_handler(int irq, void *data)
+{
+ struct da7280_haptic *haptics = data;
+ u8 events[IRQ_NUM];
+ int error;
+
+ /* Check what events have happened */
+ error = regmap_bulk_read(haptics->regmap,
+ DA7280_IRQ_EVENT1,
+ events, IRQ_NUM);
+ if (error)
+ goto error_i2c;
+
+ /* Empty check due to shared interrupt */
+ if ((events[0] | events[1] | events[2]) == 0x00)
+ return IRQ_HANDLED;
+
+ if (events[0] & DA7280_E_SEQ_FAULT_MASK) {
+ /* Stop first if Haptic is working
+ * Otherwise, the fault may happen continually
+ * even though the bit is cleared.
+ */
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_OPERATION_MODE_MASK, 0);
+ if (error)
+ goto error_i2c;
+ }
+
+ /* Clear events */
+ error = regmap_write(haptics->regmap,
+ DA7280_IRQ_EVENT1, events[0]);
+ if (error)
+ goto error_i2c;
+
+ return IRQ_HANDLED;
+
+error_i2c:
+ dev_err(haptics->dev, "da7280 i2c error : %d\n", error);
+ return IRQ_NONE;
+}
+
+static int da7280_init(struct da7280_haptic *haptics)
+{
+ int error, i;
+ unsigned int val = 0;
+ u32 v2i_factor;
+ u8 mask = 0;
+
+ /* If device type is DA7280_DEV_MAX,
+ * then just use default value inside chip.
+ */
+ if (haptics->dev_type == DA7280_DEV_MAX) {
+ error = regmap_read(haptics->regmap, DA7280_TOP_CFG1, &val);
+ if (error)
+ goto error_i2c;
+ if (val & DA7280_ACTUATOR_TYPE_MASK)
+ haptics->dev_type = DA7280_ERM_COIN;
+ else
+ haptics->dev_type = DA7280_LRA;
+ }
+
+ /* Apply user settings */
+ if (haptics->dev_type == DA7280_LRA) {
+ if (haptics->resonant_freq_l != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap,
+ DA7280_FRQ_LRA_PER_H,
+ haptics->resonant_freq_h);
+ if (error)
+ goto error_i2c;
+ error = regmap_write(haptics->regmap,
+ DA7280_FRQ_LRA_PER_L,
+ haptics->resonant_freq_l);
+ if (error)
+ goto error_i2c;
+ }
+ } else if (haptics->dev_type == DA7280_ERM_COIN) {
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_INT_CFG1,
+ DA7280_BEMF_FAULT_LIM_MASK, 0);
+ if (error)
+ goto error_i2c;
+
+ mask = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
+ DA7280_V2I_FACTOR_FREEZE_MASK;
+ val = DA7280_TST_CALIB_IMPEDANCE_DIS_MASK |
+ DA7280_V2I_FACTOR_FREEZE_MASK;
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CFG4,
+ mask, val);
+ if (error)
+ goto error_i2c;
+
+ haptics->acc_en = false;
+ haptics->rapid_stop_en = false;
+ haptics->amp_pid_en = false;
+ }
+
+ /* Should be set to 0 only
+ * in custom waveform and wideband operation
+ */
+ if (haptics->op_mode >= DA7280_RTWM_MODE)
+ haptics->bemf_sense_en = false;
+
+ mask = DA7280_ACTUATOR_TYPE_MASK |
+ DA7280_BEMF_SENSE_EN_MASK |
+ DA7280_FREQ_TRACK_EN_MASK |
+ DA7280_ACCELERATION_EN_MASK |
+ DA7280_RAPID_STOP_EN_MASK |
+ DA7280_AMP_PID_EN_MASK;
+
+ val = (haptics->dev_type ? 1 : 0)
+ << DA7280_ACTUATOR_TYPE_SHIFT |
+ (haptics->bemf_sense_en ? 1 : 0)
+ << DA7280_BEMF_SENSE_EN_SHIFT |
+ (haptics->freq_track_en ? 1 : 0)
+ << DA7280_FREQ_TRACK_EN_SHIFT |
+ (haptics->acc_en ? 1 : 0)
+ << DA7280_ACCELERATION_EN_SHIFT |
+ (haptics->rapid_stop_en ? 1 : 0)
+ << DA7280_RAPID_STOP_EN_SHIFT |
+ (haptics->amp_pid_en ? 1 : 0)
+ << DA7280_AMP_PID_EN_SHIFT;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CFG1, mask, val);
+ if (error)
+ goto error_i2c;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CFG5,
+ DA7280_V2I_FACTOR_OFFSET_EN_MASK,
+ haptics->acc_en ?
+ DA7280_V2I_FACTOR_OFFSET_EN_MASK : 0);
+ if (error)
+ goto error_i2c;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CFG2,
+ DA7280_MEM_DATA_SIGNED_MASK,
+ haptics->acc_en ?
+ 0 : DA7280_MEM_DATA_SIGNED_MASK);
+ if (error)
+ goto error_i2c;
+
+ if (haptics->nommax != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap,
+ DA7280_ACTUATOR1,
+ haptics->nommax);
+ if (error)
+ goto error_i2c;
+ }
+
+ if (haptics->absmax != DA7280_SKIP_INIT) {
+ error = regmap_write(haptics->regmap, DA7280_ACTUATOR2,
+ haptics->absmax);
+ if (error)
+ goto error_i2c;
+ }
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_ACTUATOR3,
+ DA7280_IMAX_MASK,
+ haptics->imax);
+ if (error)
+ goto error_i2c;
+
+ v2i_factor =
+ haptics->impd * (haptics->imax + 4) / 1610400;
+ error = regmap_write(haptics->regmap,
+ DA7280_CALIB_V2I_L,
+ v2i_factor & 0xff);
+ if (error)
+ goto error_i2c;
+ error = regmap_write(haptics->regmap,
+ DA7280_CALIB_V2I_H,
+ v2i_factor >> 8);
+ if (error)
+ goto error_i2c;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK,
+ DA7280_STANDBY_EN_MASK);
+ if (error)
+ goto error_i2c;
+
+ if (haptics->mem_update) {
+ error = da7280_haptic_mem_update(haptics);
+ if (error)
+ goto error_i2c;
+ }
+
+ /* Set PS_SEQ_ID and PS_SEQ_LOOP */
+ val = haptics->ps_seq_id << DA7280_PS_SEQ_ID_SHIFT |
+ haptics->ps_seq_loop << DA7280_PS_SEQ_LOOP_SHIFT;
+ error = regmap_write(haptics->regmap,
+ DA7280_SEQ_CTL2, val);
+ if (error)
+ goto error_i2c;
+
+ /* GPI(N) CTL */
+ for (i = 0; i < 3; i++) {
+ val = haptics->gpi_ctl[i].seq_id
+ << DA7280_GPI0_SEQUENCE_ID_SHIFT |
+ haptics->gpi_ctl[i].mode
+ << DA7280_GPI0_MODE_SHIFT |
+ haptics->gpi_ctl[i].polarity
+ << DA7280_GPI0_POLARITY_SHIFT;
+ error = regmap_write(haptics->regmap,
+ DA7280_GPI_0_CTL + i, val);
+ if (error)
+ goto error_i2c;
+ }
+
+ /* Clear Interrupts */
+ error = regmap_write(haptics->regmap, DA7280_IRQ_EVENT1, 0xff);
+ if (error)
+ goto error_i2c;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_IRQ_MASK1,
+ DA7280_SEQ_FAULT_M_MASK
+ | DA7280_SEQ_DONE_M_MASK, 0);
+ if (error)
+ goto error_i2c;
+
+ haptics->enabled = false;
+ return 0;
+
+error_i2c:
+ dev_err(haptics->dev, "haptic init - I2C error : %d\n", error);
+ return error;
+}
+
+/* Valid format for ps_seq_id
+ * echo X > ps_seq_id
+ * ex) echo 2 > /sys/class/..../ps_seq_id
+ * 0 <= X <= 15.
+ */
+static ssize_t ps_seq_id_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ long val = 0xff;
+ int error;
+
+ if (kstrtol(&buf[0], 0, &val) < 0)
+ goto err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_SEQ_CTL2,
+ DA7280_PS_SEQ_ID_MASK,
+ (val & 0xf) >> DA7280_PS_SEQ_ID_SHIFT);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to update register : %d\n", error);
+ return error;
+ }
+
+ haptics->ps_seq_id = val & 0xf;
+
+ return count;
+
+err:
+ dev_err(dev, "Invalid input\n");
+ return count;
+}
+
+static ssize_t ps_seq_id_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error;
+ unsigned int val;
+
+ error = regmap_read(haptics->regmap, DA7280_SEQ_CTL2, &val);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to read register : %d\n", error);
+ return error;
+ }
+ val = (val & DA7280_PS_SEQ_ID_MASK)
+ >> DA7280_PS_SEQ_ID_SHIFT;
+
+ return sprintf(buf, "ps_seq_id is %d\n", val);
+}
+
+/* Valid format for ps_seq_loop
+ * echo X > ps_seq_loop
+ * ex) echo 2 > /sys/class/..../ps_seq_loop
+ * 0 <= X <= 15.
+ */
+static ssize_t ps_seq_loop_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ long val = 0xff;
+ int error;
+
+ if (kstrtol(&buf[0], 0, &val) < 0)
+ goto err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_SEQ_CTL2,
+ DA7280_PS_SEQ_LOOP_MASK,
+ (val & 0xF) << DA7280_PS_SEQ_LOOP_SHIFT);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to update register : %d\n", error);
+ return error;
+ }
+
+ haptics->ps_seq_loop = (val & 0xF);
+
+ return count;
+err:
+ dev_err(dev, "Invalid input value!\n");
+ return count;
+}
+
+static ssize_t ps_seq_loop_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error;
+ unsigned int val;
+
+ error = regmap_read(haptics->regmap, DA7280_SEQ_CTL2, &val);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to read register : %d\n", error);
+ return error;
+ }
+ val = (val & DA7280_PS_SEQ_LOOP_MASK)
+ >> DA7280_PS_SEQ_LOOP_SHIFT;
+
+ return sprintf(buf, "ps_seq_loop is %d\n", val);
+}
+
+/* Valid format for GPIx_SEQUENCE_ID
+ * echo X > ./gpi_seq_id0
+ * Range of X: 0 <= X <= 15
+ * ex)
+ * echo 1 > /sys/class/..../gpi_seq_id0
+ * echo 2 > /sys/class/..../gpi_seq_id1
+ * echo 3 > /sys/class/..../gpi_seq_id2
+ */
+static ssize_t gpi_seq_id0_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ long val = 0xff;
+ int error;
+
+ if (kstrtol(&buf[0], 0, &val) < 0)
+ goto err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_GPI_0_CTL,
+ DA7280_GPI0_SEQUENCE_ID_MASK,
+ (val & 0xf)
+ << DA7280_GPI0_SEQUENCE_ID_SHIFT);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to update register : %d\n", error);
+ return error;
+ }
+
+ haptics->gpi_ctl[0].seq_id = val & 0xf;
+
+ return count;
+
+err:
+ dev_err(dev, "Invalid input\n");
+ return count;
+}
+
+static ssize_t gpi_seq_id0_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error;
+ unsigned int val;
+
+ error = regmap_read(haptics->regmap, DA7280_GPI_0_CTL, &val);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to read register : %d\n", error);
+ return error;
+ }
+ val = (val & DA7280_GPI0_SEQUENCE_ID_MASK)
+ >> DA7280_GPI0_SEQUENCE_ID_SHIFT;
+
+ return sprintf(buf, "gpi_seq_id0 is %d\n", val);
+}
+
+static ssize_t gpi_seq_id1_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ long val = 0xff;
+ int error;
+
+ if (kstrtol(&buf[0], 0, &val) < 0)
+ goto err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_GPI_1_CTL,
+ DA7280_GPI1_SEQUENCE_ID_MASK,
+ (val & 0xf)
+ << DA7280_GPI1_SEQUENCE_ID_SHIFT);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to update register : %d\n", error);
+ return error;
+ }
+
+ haptics->gpi_ctl[1].seq_id = val & 0xf;
+
+ return count;
+
+err:
+ dev_err(dev, "Invalid input\n");
+ return count;
+}
+
+static ssize_t gpi_seq_id1_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error;
+ unsigned int val;
+
+ error = regmap_read(haptics->regmap, DA7280_GPI_1_CTL, &val);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to read register : %d\n", error);
+ return error;
+ }
+ val = (val & DA7280_GPI1_SEQUENCE_ID_MASK)
+ >> DA7280_GPI1_SEQUENCE_ID_SHIFT;
+
+ return sprintf(buf, "gpi_seq_id1 is %d\n", val);
+}
+
+static ssize_t gpi_seq_id2_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ long val = 0xff;
+ int error;
+
+ if (kstrtol(&buf[0], 0, &val) < 0)
+ goto err;
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_GPI_2_CTL,
+ DA7280_GPI2_SEQUENCE_ID_MASK,
+ (val & 0xf)
+ << DA7280_GPI2_SEQUENCE_ID_SHIFT);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to update register : %d\n", error);
+ return error;
+ }
+
+ haptics->gpi_ctl[2].seq_id = val & 0xf;
+
+ return count;
+
+err:
+ dev_err(dev, "Invalid input\n");
+ return count;
+}
+
+static ssize_t gpi_seq_id2_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error;
+ unsigned int val;
+
+ error = regmap_read(haptics->regmap, DA7280_GPI_2_CTL, &val);
+ if (error) {
+ dev_err(haptics->dev,
+ "failed to read register : %d\n", error);
+ return error;
+ }
+ val = (val & DA7280_GPI2_SEQUENCE_ID_MASK)
+ >> DA7280_GPI2_SEQUENCE_ID_SHIFT;
+
+ return sprintf(buf, "gpi_seq_id2 is %d\n", val);
+}
+
+#define MAX_PTN_REGS DA7280_SNP_MEM_SIZE
+#define MAX_USER_INPUT_LEN (5 * DA7280_SNP_MEM_SIZE)
+struct parse_data_t {
+ int len;
+ u8 val[MAX_PTN_REGS];
+};
+
+static int da7280_parse_args(struct device *dev,
+ char *cmd, struct parse_data_t *ptn)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ char *tok; /* used to separate tokens */
+ const char ct[] = " \t"; /* space or tab delimits the tokens */
+ int tok_count = 0; /* total number of tokens parsed */
+ int i = 0, val;
+
+ ptn->len = 0;
+
+ /* parse the input string */
+ while ((tok = strsep(&cmd, ct)) != NULL) {
+ /* this is a value to be written to the register */
+ if (kstrtouint(tok, 0, &val) < 0) {
+ dev_err(haptics->dev,
+ "failed to read from %s\n", tok);
+ break;
+ }
+
+ if (i < MAX_PTN_REGS) {
+ ptn->val[i] = val;
+ i++;
+ }
+ tok_count++;
+ }
+
+ /* decide whether it is a read or write operation based on the
+ * value of tok_count and count_flag.
+ * tok_count = 0: no inputs, invalid case.
+ * tok_count = 1: write one value.
+ * tok_count > 1: write multiple values/patterns.
+ */
+ switch (tok_count) {
+ case 0:
+ return -EINVAL;
+ case 1:
+ ptn->len = 1;
+ break;
+ default:
+ ptn->len = i;
+ }
+ return 0;
+}
+
+static ssize_t
+patterns_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ struct parse_data_t mem;
+ char cmd[MAX_USER_INPUT_LEN];
+ unsigned int val;
+ int error;
+
+ error = regmap_read(haptics->regmap, DA7280_MEM_CTL1, &val);
+ if (error)
+ return error;
+
+ if (count > MAX_USER_INPUT_LEN)
+ memcpy(cmd, buf, MAX_USER_INPUT_LEN);
+ else
+ memcpy(cmd, buf, count);
+
+ /* chop of '\n' introduced by echo at the end of the input */
+ if (cmd[count - 1] == '\n')
+ cmd[count - 1] = '\0';
+
+ if (da7280_parse_args(dev, cmd, &mem) < 0)
+ return -EINVAL;
+
+ memcpy(haptics->snp_mem, mem.val, mem.len);
+
+ error = da7280_haptic_mem_update(haptics);
+ if (error)
+ return error;
+
+ return count;
+}
+
+static DEVICE_ATTR_RW(ps_seq_id);
+static DEVICE_ATTR_RW(ps_seq_loop);
+static DEVICE_ATTR_RW(gpi_seq_id0);
+static DEVICE_ATTR_RW(gpi_seq_id1);
+static DEVICE_ATTR_RW(gpi_seq_id2);
+static DEVICE_ATTR_WO(patterns);
+static struct attribute *da7280_sysfs_attr[] = {
+ &dev_attr_ps_seq_id.attr,
+ &dev_attr_ps_seq_loop.attr,
+ &dev_attr_gpi_seq_id0.attr,
+ &dev_attr_gpi_seq_id1.attr,
+ &dev_attr_gpi_seq_id2.attr,
+ &dev_attr_patterns.attr,
+ NULL,
+};
+
+static const struct attribute_group da7280_attr_group = {
+ .attrs = da7280_sysfs_attr,
+};
+
+static int da7280_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct da7280_haptic *haptics;
+ unsigned int period2freq;
+ int error;
+
+ haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
+ if (!haptics)
+ return -ENOMEM;
+ haptics->dev = dev;
+
+ if (!client->irq) {
+ dev_err(dev, "No IRQ configured\n");
+ return -EINVAL;
+ }
+
+ da7280_parse_properties(&client->dev, haptics);
+
+ if (haptics->op_mode == DA7280_PWM_MODE) {
+ /* Get pwm and regulatot for haptics device */
+ haptics->pwm_dev = devm_pwm_get(&client->dev, NULL);
+ if (IS_ERR(haptics->pwm_dev)) {
+ dev_err(dev, "failed to get PWM device\n");
+ return PTR_ERR(haptics->pwm_dev);
+ }
+
+ /*
+ * FIXME: pwm_apply_args() should be removed when switching to
+ * the atomic PWM API.
+ */
+ pwm_apply_args(haptics->pwm_dev);
+
+ /* Check PWM Period, it must be in 10k ~ 250kHz */
+ period2freq = 1000000 / pwm_get_period(haptics->pwm_dev);
+ if (period2freq < DA7280_MIN_PWM_FREQ_KHZ ||
+ period2freq > DA7280_MAX_PWM_FREQ_KHZ) {
+ dev_err(dev, "Not supported PWM frequency(%d)\n",
+ period2freq);
+ return -EINVAL;
+ }
+ }
+
+ INIT_WORK(&haptics->work, da7280_haptic_work);
+ haptics->client = client;
+ i2c_set_clientdata(client, haptics);
+
+ haptics->regmap =
+ devm_regmap_init_i2c(client, &da7280_haptic_regmap_config);
+ if (IS_ERR(haptics->regmap)) {
+ error = PTR_ERR(haptics->regmap);
+ dev_err(dev, "Failed to allocate register map : %d\n",
+ error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, client->irq, NULL,
+ da7280_irq_handler,
+ IRQF_ONESHOT,
+ "da7280-haptics", haptics);
+ if (error != 0) {
+ dev_err(dev,
+ "Failed to request IRQ : %d\n", client->irq);
+ return error;
+ }
+
+ error = da7280_init(haptics);
+ if (error) {
+ dev_err(dev, "failed to initialize device\n");
+ return error;
+ }
+
+ /* Initialize input device for haptic device */
+ haptics->input_dev = devm_input_allocate_device(dev);
+ if (!haptics->input_dev) {
+ dev_err(dev, "failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ haptics->input_dev->name = "da7280-haptic";
+ haptics->input_dev->dev.parent = client->dev.parent;
+ haptics->input_dev->open = da7280_haptic_open;
+ haptics->input_dev->close = da7280_haptic_close;
+ input_set_drvdata(haptics->input_dev, haptics);
+ input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+ error = input_ff_create_memless(haptics->input_dev, NULL,
+ da7280_haptic_play);
+ if (error) {
+ dev_err(dev, "failed to create force-feedback\n");
+ return error;
+ }
+
+ error = input_register_device(haptics->input_dev);
+ if (error) {
+ dev_err(dev, "failed to register input device\n");
+ return error;
+ }
+
+ error = devm_device_add_group(dev, &da7280_attr_group);
+ if (error) {
+ dev_err(dev, "Failed to create sysfs attributes: %d\n",
+ error);
+ }
+
+ return error;
+}
+
+static int __maybe_unused da7280_suspend(struct device *dev)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ da7280_haptic_disable(haptics);
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK, 0);
+ if (error)
+ dev_err(haptics->dev,
+ "I2C error : %d\n", error);
+
+ mutex_unlock(&haptics->input_dev->mutex);
+ return error;
+}
+
+static int __maybe_unused da7280_resume(struct device *dev)
+{
+ struct da7280_haptic *haptics = dev_get_drvdata(dev);
+ int error = 0;
+
+ mutex_lock(&haptics->input_dev->mutex);
+
+ error = regmap_update_bits(haptics->regmap,
+ DA7280_TOP_CTL1,
+ DA7280_STANDBY_EN_MASK,
+ DA7280_STANDBY_EN_MASK);
+ if (error)
+ dev_err(haptics->dev,
+ "i2c error : %d\n", error);
+
+ mutex_unlock(&haptics->input_dev->mutex);
+ return error;
+}
+
+static const struct of_device_id da7280_of_match[] = {
+ { .compatible = "dlg,da7280", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da7280_of_match);
+
+static const struct i2c_device_id da7280_i2c_id[] = {
+ { "da7280", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
+
+static SIMPLE_DEV_PM_OPS(da7280_pm_ops,
+ da7280_suspend, da7280_resume);
+
+static struct i2c_driver da7280_driver = {
+ .driver = {
+ .name = "da7280",
+ .of_match_table = of_match_ptr(da7280_of_match),
+ .pm = &da7280_pm_ops,
+ },
+ .probe = da7280_probe,
+ .id_table = da7280_i2c_id,
+};
+module_i2c_driver(da7280_driver);
+
+MODULE_DESCRIPTION("DA7280 haptics driver");
+MODULE_AUTHOR("Roy Im <Roy.Im.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/da7280.h b/drivers/input/misc/da7280.h
new file mode 100644
index 0000000..d9310b6
--- /dev/null
+++ b/drivers/input/misc/da7280.h
@@ -0,0 +1,412 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * DA7280 Haptic device driver registers
+ *
+ * Copyright (c) 2017 Dialog Semiconductor.
+ * Author: Roy Im <Roy.Im.Opensource@diasemi.com>
+ */
+
+#ifndef _DA7280_REG_DEFS_H
+#define _DA7280_REG_DEFS_H
+
+#include <linux/bitops.h>
+
+/* Registers */
+
+#define DA7280_CHIP_REV 0x00
+#define DA7280_IRQ_EVENT1 0x03
+#define DA7280_IRQ_EVENT_WARNING_DIAG 0x04
+#define DA7280_IRQ_EVENT_SEQ_DIAG 0x05
+#define DA7280_IRQ_STATUS1 0x06
+#define DA7280_IRQ_MASK1 0x07
+#define DA7280_CIF_I2C1 0x08
+#define DA7280_FRQ_LRA_PER_H 0x0A
+#define DA7280_FRQ_LRA_PER_L 0x0B
+#define DA7280_ACTUATOR1 0x0C
+#define DA7280_ACTUATOR2 0x0D
+#define DA7280_ACTUATOR3 0x0E
+#define DA7280_CALIB_V2I_H 0x0F
+#define DA7280_CALIB_V2I_L 0x10
+#define DA7280_CALIB_IMP_H 0x11
+#define DA7280_CALIB_IMP_L 0x12
+#define DA7280_TOP_CFG1 0x13
+#define DA7280_TOP_CFG2 0x14
+#define DA7280_TOP_CFG3 0x15
+#define DA7280_TOP_CFG4 0x16
+#define DA7280_TOP_INT_CFG1 0x17
+#define DA7280_TOP_INT_CFG6_H 0x1C
+#define DA7280_TOP_INT_CFG6_L 0x1D
+#define DA7280_TOP_INT_CFG7_H 0x1E
+#define DA7280_TOP_INT_CFG7_L 0x1F
+#define DA7280_TOP_INT_CFG8 0x20
+#define DA7280_TOP_CTL1 0x22
+#define DA7280_TOP_CTL2 0x23
+#define DA7280_SEQ_CTL1 0x24
+#define DA7280_SWG_C1 0x25
+#define DA7280_SWG_C2 0x26
+#define DA7280_SWG_C3 0x27
+#define DA7280_SEQ_CTL2 0x28
+#define DA7280_GPI_0_CTL 0x29
+#define DA7280_GPI_1_CTL 0x2A
+#define DA7280_GPI_2_CTL 0x2B
+#define DA7280_MEM_CTL1 0x2C
+#define DA7280_MEM_CTL2 0x2D
+#define DA7280_ADC_DATA_H1 0x2E
+#define DA7280_ADC_DATA_L1 0x2F
+#define DA7280_POLARITY 0x43
+#define DA7280_LRA_AVR_H 0x44
+#define DA7280_LRA_AVR_L 0x45
+#define DA7280_FRQ_LRA_PER_ACT_H 0x46
+#define DA7280_FRQ_LRA_PER_ACT_L 0x47
+#define DA7280_FRQ_PHASE_H 0x48
+#define DA7280_FRQ_PHASE_L 0x49
+#define DA7280_FRQ_CTL 0x4C
+#define DA7280_TRIM3 0x5F
+#define DA7280_TRIM4 0x60
+#define DA7280_TRIM6 0x62
+#define DA7280_TOP_CFG5 0x6E
+#define DA7280_IRQ_EVENT_ACTUATOR_FAULT 0x81
+#define DA7280_IRQ_STATUS2 0x82
+#define DA7280_IRQ_MASK2 0x83
+#define DA7280_SNP_MEM_0 0x84
+#define DA7280_SNP_MEM_99 0xE7
+
+/* DA7280_CHIP_REV (Address 0x00) */
+#define DA7280_CHIP_REV_MAJOR_SHIFT 0
+#define DA7280_CHIP_REV_MAJOR_MASK (15 << 0)
+#define DA7280_CHIP_REV_MINOR_SHIFT 4
+#define DA7280_CHIP_REV_MINOR_MASK (15 << 4)
+
+/* DA7280_IRQ_EVENT1 (Address 0x03) */
+#define DA7280_E_SEQ_CONTINUE_SHIFT 0
+#define DA7280_E_SEQ_CONTINUE_MASK BIT(0)
+#define DA7280_E_UVLO_SHIFT 1
+#define DA7280_E_UVLO_MASK BIT(1)
+#define DA7280_E_SEQ_DONE_SHIFT 2
+#define DA7280_E_SEQ_DONE_MASK BIT(2)
+#define DA7280_E_OVERTEMP_CRIT_SHIFT 3
+#define DA7280_E_OVERTEMP_CRIT_MASK BIT(3)
+#define DA7280_E_SEQ_FAULT_SHIFT 4
+#define DA7280_E_SEQ_FAULT_MASK BIT(4)
+#define DA7280_E_WARNING_SHIFT 5
+#define DA7280_E_WARNING_MASK BIT(5)
+#define DA7280_E_ACTUATOR_FAULT_SHIFT 6
+#define DA7280_E_ACTUATOR_FAULT_MASK BIT(6)
+#define DA7280_E_OC_FAULT_SHIFT 7
+#define DA7280_E_OC_FAULT_MASK BIT(7)
+
+/* DA7280_IRQ_EVENT_WARNING_DIAG (Address 0x04) */
+#define DA7280_E_OVERTEMP_WARN_SHIFT 3
+#define DA7280_E_OVERTEMP_WARN_MASK BIT(3)
+#define DA7280_E_MEM_TYPE_SHIFT 4
+#define DA7280_E_MEM_TYPE_MASK BIT(4)
+#define DA7280_E_LIM_DRIVE_ACC_SHIFT 6
+#define DA7280_E_LIM_DRIVE_ACC_MASK BIT(6)
+#define DA7280_E_LIM_DRIVE_SHIFT 7
+#define DA7280_E_LIM_DRIVE_MASK BIT(7)
+
+/* DA7280_IRQ_EVENT_PAT_DIAG (Address 0x05) */
+#define DA7280_E_PWM_FAULT_SHIFT 5
+#define DA7280_E_PWM_FAULT_MASK BIT(5)
+#define DA7280_E_MEM_FAULT_SHIFT 6
+#define DA7280_E_MEM_FAULT_MASK BIT(6)
+#define DA7280_E_SEQ_ID_FAULT_SHIFT 7
+#define DA7280_E_SEQ_ID_FAULT_MASK BIT(7)
+
+/* DA7280_IRQ_STATUS1 (Address 0x06) */
+#define DA7280_STA_SEQ_CONTINUE_SHIFT 0
+#define DA7280_STA_SEQ_CONTINUE_MASK BIT(0)
+#define DA7280_STA_UVLO_VBAT_OK_SHIFT 1
+#define DA7280_STA_UVLO_VBAT_OK_MASK BIT(1)
+#define DA7280_STA_SEQ_DONE_SHIFT 2
+#define DA7280_STA_SEQ_DONE_MASK BIT(2)
+#define DA7280_STA_OVERTEMP_CRIT_SHIFT 3
+#define DA7280_STA_OVERTEMP_CRIT_MASK BIT(3)
+#define DA7280_STA_SEQ_FAULT_SHIFT 4
+#define DA7280_STA_SEQ_FAULT_MASK BIT(4)
+#define DA7280_STA_WARNING_SHIFT 5
+#define DA7280_STA_WARNING_MASK BIT(5)
+#define DA7280_STA_ACTUATOR_SHIFT 6
+#define DA7280_STA_ACTUATOR_MASK BIT(6)
+#define DA7280_STA_OC_SHIFT 7
+#define DA7280_STA_OC_MASK BIT(7)
+
+/* DA7280_IRQ_MASK1 (Address 0x07) */
+#define DA7280_SEQ_CONTINUE_M_SHIFT 0
+#define DA7280_SEQ_CONTINUE_M_MASK BIT(0)
+#define DA7280_E_UVLO_M_SHIFT 1
+#define DA7280_E_UVLO_M_MASK BIT(1)
+#define DA7280_SEQ_DONE_M_SHIFT 2
+#define DA7280_SEQ_DONE_M_MASK BIT(2)
+#define DA7280_OVERTEMP_CRIT_M_SHIFT 3
+#define DA7280_OVERTEMP_CRIT_M_MASK BIT(3)
+#define DA7280_SEQ_FAULT_M_SHIFT 4
+#define DA7280_SEQ_FAULT_M_MASK BIT(4)
+#define DA7280_WARNING_M_SHIFT 5
+#define DA7280_WARNING_M_MASK BIT(5)
+#define DA7280_ACTUATOR_M_SHIFT 6
+#define DA7280_ACTUATOR_M_MASK BIT(6)
+#define DA7280_OC_M_SHIFT 7
+#define DA7280_OC_M_MASK BIT(7)
+
+/* DA7280_CIF_I2C1 (Address 0x08) */
+#define DA7280_I2C_TO_ENABLE_SHIFT 6
+#define DA7280_I2C_TO_ENABLE_MASK BIT(6)
+#define DA7280_I2C_WR_MODE_SHIFT 7
+#define DA7280_I2C_WR_MODE_MASK BIT(7)
+
+/* DA7280_FRQ_LRA_PER_H (Address 0x0a) */
+#define DA7280_LRA_PER_H_SHIFT 0
+#define DA7280_LRA_PER_H_MASK (255 << 0)
+
+/* DA7280_FRQ_LRA_PER_L (Address 0x0b) */
+#define DA7280_LRA_PER_L_SHIFT 0
+#define DA7280_LRA_PER_L_MASK (127 << 0)
+
+/* DA7280_ACTUATOR1 (Address 0x0c) */
+#define DA7280_ACTUATOR_NOMMAX_SHIFT 0
+#define DA7280_ACTUATOR_NOMMAX_MASK (255 << 0)
+
+/* DA7280_ACTUATOR2 (Address 0x0d) */
+#define DA7280_ACTUATOR_ABSMAX_SHIFT 0
+#define DA7280_ACTUATOR_ABSMAX_MASK (255 << 0)
+
+/* DA7280_ACTUATOR3 (Address 0x0e) */
+#define DA7280_IMAX_SHIFT 0
+#define DA7280_IMAX_MASK (31 << 0)
+
+/* DA7280_CALIB_V2I_H (Address 0x0f) */
+#define DA7280_V2I_FACTOR_H_SHIFT 0
+#define DA7280_V2I_FACTOR_H_MASK (255 << 0)
+
+/* DA7280_CALIB_V2I_L (Address 0x10) */
+#define DA7280_V2I_FACTOR_L_SHIFT 0
+#define DA7280_V2I_FACTOR_L_MASK (255 << 0)
+
+/* DA7280_CALIB_IMP_H (Address 0x11) */
+#define DA7280_IMPEDANCE_H_SHIFT 0
+#define DA7280_IMPEDANCE_H_MASK (255 << 0)
+
+/* DA7280_CALIB_IMP_L (Address 0x12) */
+#define DA7280_IMPEDANCE_L_SHIFT 0
+#define DA7280_IMPEDANCE_L_MASK (3 << 0)
+
+/* DA7280_TOP_CFG1 (Address 0x13) */
+#define DA7280_AMP_PID_EN_SHIFT 0
+#define DA7280_AMP_PID_EN_MASK BIT(0)
+#define DA7280_RAPID_STOP_EN_SHIFT 1
+#define DA7280_RAPID_STOP_EN_MASK BIT(1)
+#define DA7280_ACCELERATION_EN_SHIFT 2
+#define DA7280_ACCELERATION_EN_MASK BIT(2)
+#define DA7280_FREQ_TRACK_EN_SHIFT 3
+#define DA7280_FREQ_TRACK_EN_MASK BIT(3)
+#define DA7280_BEMF_SENSE_EN_SHIFT 4
+#define DA7280_BEMF_SENSE_EN_MASK BIT(4)
+#define DA7280_ACTUATOR_TYPE_SHIFT 5
+#define DA7280_ACTUATOR_TYPE_MASK BIT(5)
+#define DA7280_EMBEDDED_MODE_SHIFT 7
+#define DA7280_EMBEDDED_MODE_MASK BIT(7)
+
+/* DA7280_TOP_CFG2 (Address 0x14) */
+#define DA7280_FULL_BRAKE_THR_SHIFT 0
+#define DA7280_FULL_BRAKE_THR_MASK (15 << 0)
+#define DA7280_MEM_DATA_SIGNED_SHIFT 4
+#define DA7280_MEM_DATA_SIGNED_MASK BIT(4)
+
+/* DA7280_TOP_CFG3 (Address 0x15) */
+#define DA7280_VDD_MARGIN_SHIFT 0
+#define DA7280_VDD_MARGIN_MASK (15 << 0)
+
+/* DA7280_TOP_CFG4 (Address 0x16) */
+#define DA7280_TST_CALIB_IMPEDANCE_DIS_SHIFT 6
+#define DA7280_TST_CALIB_IMPEDANCE_DIS_MASK BIT(6)
+#define DA7280_V2I_FACTOR_FREEZE_SHIFT 7
+#define DA7280_V2I_FACTOR_FREEZE_MASK BIT(7)
+
+/* DA7280_TOP_INT_CFG1 (Address 0x17) */
+#define DA7280_BEMF_FAULT_LIM_SHIFT 0
+#define DA7280_BEMF_FAULT_LIM_MASK (3 << 0)
+#define DA7280_FRQ_LOCKED_LIM_SHIFT 2
+#define DA7280_FRQ_LOCKED_LIM_MASK (63 << 2)
+
+/* DA7280_TOP_INT_CFG6_H (Address 0x1c) */
+#define DA7280_FRQ_PID_KP_H_SHIFT 0
+#define DA7280_FRQ_PID_KP_H_MASK (255 << 0)
+
+/* DA7280_TOP_INT_CFG6_L (Address 0x1d) */
+#define DA7280_FRQ_PID_KP_L_SHIFT 0
+#define DA7280_FRQ_PID_KP_L_MASK (255 << 0)
+
+/* DA7280_TOP_INT_CFG7_H (Address 0x1e) */
+#define DA7280_FRQ_PID_KI_H_SHIFT 0
+#define DA7280_FRQ_PID_KI_H_MASK (255 << 0)
+
+/* DA7280_TOP_INT_CFG7_L (Address 0x1f) */
+#define DA7280_FRQ_PID_KI_L_SHIFT 0
+#define DA7280_FRQ_PID_KI_L_MASK (255 << 0)
+
+/* DA7280_TOP_INT_CFG8 (Address 0x20) */
+#define DA7280_TST_FRQ_TRACK_BEMF_LIM_SHIFT 0
+#define DA7280_TST_FRQ_TRACK_BEMF_LIM_MASK (15 << 0)
+#define DA7280_TST_AMP_RAPID_STOP_LIM_SHIFT 4
+#define DA7280_TST_AMP_RAPID_STOP_LIM_MASK (7 << 4)
+
+/* DA7280_TOP_CTL1 (Address 0x22) */
+#define DA7280_OPERATION_MODE_SHIFT 0
+#define DA7280_OPERATION_MODE_MASK (7 << 0)
+#define DA7280_STANDBY_EN_SHIFT 3
+#define DA7280_STANDBY_EN_MASK BIT(3)
+#define DA7280_SEQ_START_SHIFT 4
+#define DA7280_SEQ_START_MASK BIT(4)
+
+/* DA7280_TOP_CTL2 (Address 0x23) */
+#define DA7280_OVERRIDE_VAL_SHIFT 0
+#define DA7280_OVERRIDE_VAL_MASK (255 << 0)
+
+/* DA7280_SEQ_CTL1 (Address 0x24) */
+#define DA7280_SEQ_CONTINUE_SHIFT 0
+#define DA7280_SEQ_CONTINUE_MASK BIT(0)
+#define DA7280_WAVEGEN_MODE_SHIFT 1
+#define DA7280_WAVEGEN_MODE_MASK BIT(1)
+#define DA7280_FREQ_WAVEFORM_TIMEBASE_SHIFT 2
+#define DA7280_FREQ_WAVEFORM_TIMEBASE_MASK BIT(2)
+
+/* DA7280_SWG_C1 (Address 0x25) */
+#define DA7280_CUSTOM_WAVE_GEN_COEFF1_SHIFT 0
+#define DA7280_CUSTOM_WAVE_GEN_COEFF1_MASK (255 << 0)
+
+/* DA7280_SWG_C2 (Address 0x26) */
+#define DA7280_CUSTOM_WAVE_GEN_COEFF2_SHIFT 0
+#define DA7280_CUSTOM_WAVE_GEN_COEFF2_MASK (255 << 0)
+
+/* DA7280_SWG_C3 (Address 0x27) */
+#define DA7280_CUSTOM_WAVE_GEN_COEFF3_SHIFT 0
+#define DA7280_CUSTOM_WAVE_GEN_COEFF3_MASK (255 << 0)
+
+/* DA7280_SEQ_CTL2 (Address 0x28) */
+#define DA7280_PS_SEQ_ID_SHIFT 0
+#define DA7280_PS_SEQ_ID_MASK (15 << 0)
+#define DA7280_PS_SEQ_LOOP_SHIFT 4
+#define DA7280_PS_SEQ_LOOP_MASK (15 << 4)
+
+/* DA7280_GPIO_0_CTL (Address 0x29) */
+#define DA7280_GPI0_POLARITY_SHIFT 0
+#define DA7280_GPI0_POLARITY_MASK (3 << 0)
+#define DA7280_GPI0_MODE_SHIFT 2
+#define DA7280_GPI0_MODE_MASK BIT(2)
+#define DA7280_GPI0_SEQUENCE_ID_SHIFT 3
+#define DA7280_GPI0_SEQUENCE_ID_MASK (15 << 3)
+
+/* DA7280_GPIO_1_CTL (Address 0x2a) */
+#define DA7280_GPI1_POLARITY_SHIFT 0
+#define DA7280_GPI1_POLARITY_MASK (3 << 0)
+#define DA7280_GPI1_MODE_SHIFT 2
+#define DA7280_GPI1_MODE_MASK BIT(2)
+#define DA7280_GPI1_SEQUENCE_ID_SHIFT 3
+#define DA7280_GPI1_SEQUENCE_ID_MASK (15 << 3)
+
+/* DA7280_GPIO_2_CTL (Address 0x2b) */
+#define DA7280_GPI2_POLARITY_SHIFT 0
+#define DA7280_GPI2_POLARITY_MASK (3 << 0)
+#define DA7280_GPI2_MODE_SHIFT 2
+#define DA7280_GPI2_MODE_MASK BIT(2)
+#define DA7280_GPI2_SEQUENCE_ID_SHIFT 3
+#define DA7280_GPI2_SEQUENCE_ID_MASK (15 << 3)
+
+/* DA7280_MEM_CTL1 (Address 0x2c) */
+#define DA7280_WAV_MEM_BASE_ADDR_SHIFT 0
+#define DA7280_WAV_MEM_BASE_ADDR_MASK (255 << 0)
+
+/* DA7280_MEM_CTL2 (Address 0x2d) */
+#define DA7280_WAV_MEM_LOCK_SHIFT 7
+#define DA7280_WAV_MEM_LOCK_MASK BIT(7)
+
+/* DA7280_ADC_DATA_H1 (Address 0x2e) */
+#define DA7280_ADC_VDD_H_SHIFT 0
+#define DA7280_ADC_VDD_H_MASK (255 << 0)
+
+/* DA7280_ADC_DATA_L1 (Address 0x2f) */
+#define DA7280_ADC_VDD_L_SHIFT 0
+#define DA7280_ADC_VDD_L_MASK (127 << 0)
+
+/* DA7280_POLARITY (Address 0x43) */
+#define DA7280_POLARITY_SHIFT 0
+#define DA7280_POLARITY_MASK BIT(0)
+
+/* DA7280_LRA_AVR_H (Address 0x44) */
+#define DA7280_LRA_PER_AVERAGE_H_SHIFT 0
+#define DA7280_LRA_PER_AVERAGE_H_MASK (255 << 0)
+
+/* DA7280_LRA_AVR_L (Address 0x45) */
+#define DA7280_LRA_PER_AVERAGE_L_SHIFT 0
+#define DA7280_LRA_PER_AVERAGE_L_MASK (127 << 0)
+
+/* DA7280_FRQ_LRA_PER_ACT_H (Address 0x46) */
+#define DA7280_LRA_PER_ACTUAL_H_SHIFT 0
+#define DA7280_LRA_PER_ACTUAL_H_MASK (255 << 0)
+
+/* DA7280_FRQ_LRA_PER_ACT_L (Address 0x47) */
+#define DA7280_LRA_PER_ACTUAL_L_SHIFT 0
+#define DA7280_LRA_PER_ACTUAL_L_MASK (127 << 0)
+
+/* DA7280_FRQ_PHASE_H (Address 0x48) */
+#define DA7280_PHASE_DELAY_H_SHIFT 0
+#define DA7280_PHASE_DELAY_H_MASK (255 << 0)
+
+/* DA7280_FRQ_PHASE_L (Address 0x49) */
+#define DA7280_DELAY_SHIFT_L_SHIFT 0
+#define DA7280_DELAY_SHIFT_L_MASK (7 << 0)
+#define DA7280_DELAY_SHIFT_FREEZE_SHIFT 7
+#define DA7280_DELAY_SHIFT_FREEZE_MASK BIT(7)
+
+/* DA7280_FRQ_CTL (Address 0x4c) */
+#define DA7280_FREQ_TRACKING_FORCE_ON_SHIFT 0
+#define DA7280_FREQ_TRACKING_FORCE_ON_MASK BIT(0)
+#define DA7280_FREQ_TRACKING_AUTO_ADJ_SHIFT 1
+#define DA7280_FREQ_TRACKING_AUTO_ADJ_MASK BIT(1)
+
+/* DA7280_TRIM3 (Address 0x5f) */
+#define DA7280_REF_UVLO_THRES_SHIFT 3
+#define DA7280_REF_UVLO_THRES_MASK (3 << 3)
+#define DA7280_LOOP_FILT_LOW_BW_SHIFT 5
+#define DA7280_LOOP_FILT_LOW_BW_MASK BIT(5)
+#define DA7280_LOOP_IDAC_DOUBLE_RANGE_SHIFT 6
+#define DA7280_LOOP_IDAC_DOUBLE_RANGE_MASK BIT(6)
+
+/* DA7280_TRIM4 (Address 0x60) */
+#define DA7280_LOOP_FILT_RES_TRIM_SHIFT 0
+#define DA7280_LOOP_FILT_RES_TRIM_MASK (3 << 0)
+#define DA7280_LOOP_FILT_CAP_TRIM_SHIFT 2
+#define DA7280_LOOP_FILT_CAP_TRIM_MASK (3 << 2)
+
+/* DA7280_TRIM6 (Address 0x62) */
+#define DA7280_HBRIDGE_ERC_HS_TRIM_SHIFT 0
+#define DA7280_HBRIDGE_ERC_HS_TRIM_MASK (3 << 0)
+#define DA7280_HBRIDGE_ERC_LS_TRIM_SHIFT 2
+#define DA7280_HBRIDGE_ERC_LS_TRIM_MASK (3 << 2)
+
+/* DA7280_TOP_CFG5 (Address 0x6e) */
+#define DA7280_V2I_FACTOR_OFFSET_EN_SHIFT 0
+#define DA7280_V2I_FACTOR_OFFSET_EN_MASK BIT(0)
+#define DA7280_FRQ_PAUSE_ON_POLARITY_CHANGE_SHIFT 1
+#define DA7280_FRQ_PAUSE_ON_POLARITY_CHANGE_MASK BIT(1)
+#define DA7280_DELAY_BYPASS_SHIFT 2
+#define DA7280_DELAY_BYPASS_MASK BIT(2)
+
+/* DA7280_IRQ_EVENT_ACTUATOR_FAULT (Address 0x81) */
+#define DA7280_ADC_SAT_FAULT_SHIFT 2
+#define DA7280_ADC_SAT_FAULT_MASK BIT(2)
+
+/* DA7280_IRQ_STATUS2 (Address 0x82) */
+#define DA7280_STA_ADC_SAT_SHIFT 7
+#define DA7280_STA_ADC_SAT_MASK BIT(7)
+
+/* DA7280_IRQ_MASK2 (Address 0x83) */
+#define DA7280_ADC_SAT_M_SHIFT 7
+#define DA7280_ADC_SAT_M_MASK BIT(7)
+
+/* DA7280_SNP_MEM_XX (Address 0x84 ~ 0xe7) */
+#define DA7280_SNP_MEM_SHIFT 0
+#define DA7280_SNP_MEM_MASK (255 << 0)
+
+#endif
--
end-of-patch for RESEND PATCH V7
^ permalink raw reply related
* [PATCH] Revert "HID: add NOGET quirk for Eaton Ellipse MAX UPS"
From: Benjamin Tissoires @ 2018-10-17 7:01 UTC (permalink / raw)
To: Jiri Kosina
Cc: Laurent Bigonville, linux-input, linux-kernel, Benjamin Tissoires
This reverts commit 67ddbb3e6568fb1820b2cc45b00c50702b114801.
67ddbb3e656 ("HID: add NOGET quirk for Eaton Ellipse MAX UPS") was reported
by Laurent Bigonville. It turns out that a later model Laurent got
doesn't need the quirk after all.
My take is that Eaton upgraded their firmwares, so we don't need it
anymore.
The old model was from 2012, so better make sure the new line works
properly by removing the quirk. This allows upower to actually fetch
the current data.
Reported-by: Laurent Bigonville <bigon@bigon.be>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/hid-quirks.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 279f410618c6..e260bdeb51a7 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -107,7 +107,6 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
- { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS), HID_QUIRK_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
--
2.14.3
^ permalink raw reply related
* Re: [PATCH] Input: synaptics - avoid using uninitialized variable when probing
From: Benjamin Tissoires @ 2018-10-17 7:03 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: open list:HID CORE LAYER, lkml
In-Reply-To: <20181017001443.GA232819@dtor-ws>
On Wed, Oct 17, 2018 at 2:14 AM Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
>
> synaptics_detect() does not check whether sending commands to the
> device succeeds and instead relies on getting unique data from the
> device. Let's make sure we seed entire buffer with zeroes to make sure
> we not use garbage on stack that just happen to be 0x47.
>
> Reported-by: syzbot+13cb3b01d0784e4ffc3f@syzkaller.appspotmail.com
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Cheers,
Benjamin
> drivers/input/mouse/synaptics.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
> index 55d33500d55e..5e85f3cca867 100644
> --- a/drivers/input/mouse/synaptics.c
> +++ b/drivers/input/mouse/synaptics.c
> @@ -99,9 +99,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode)
> int synaptics_detect(struct psmouse *psmouse, bool set_properties)
> {
> struct ps2dev *ps2dev = &psmouse->ps2dev;
> - u8 param[4];
> -
> - param[0] = 0;
> + u8 param[4] = { 0 };
>
> ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
> --
> 2.19.1.331.ge82ca0e54c-goog
>
>
> --
> Dmitry
^ permalink raw reply
* [PATCH v2 0/7] Input: sx8654 - reset-gpio, sx865[056] support, etc.
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
Add reset-gpio, sx8654[056] and common of_touchscreen functions support
for the sx8654 driver.
Changes v2:
- use devm_gpiod_get_optional in probe instead of in #ifdef CONFIG_OF
- convert flags to BIT() in a separate patch
- replace hrtimer with "regular" timer
- use of_device_get_match_data instead of of_match_device
- add driver data to i2c_device_id table for non-DT fallback
- fix sequence of common touchscreen initialization
- div. minor stlye changes
Richard Leitner (8):
dt-bindings: input: touchscreen: sx8654: add reset-gpio property
Input: sx8654 - add reset-gpio support
dt-bindings: input: touchscreen: sx8654: add compatible models
Input: sx8654 - add sx8655 and sx8656 to compatibles
dt-bindings: input: touchscreen: sx8654: add sx8650 to comatibles
Input: sx8654 - add sx8650 support
Input: sx8654 - use common of_touchscreen functions
Input: sx8654 - convert #defined flags to BIT(x)
.../bindings/input/touchscreen/sx8654.txt | 10 +-
drivers/input/touchscreen/sx8654.c | 245 ++++++++++++++++++---
2 files changed, 229 insertions(+), 26 deletions(-)
--
2.11.0
^ permalink raw reply
* [PATCH v2 1/8] dt-bindings: input: touchscreen: sx8654: add reset-gpio property
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
Document the reset-gpio property for the sx8654 touchscreen controller
driver.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
Documentation/devicetree/bindings/input/touchscreen/sx8654.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
index 4886c4aa2906..ca521d8f7d65 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
@@ -5,6 +5,9 @@ Required properties:
- reg: i2c slave address
- interrupts: touch controller interrupt
+Optional properties:
+ - reset-gpios: GPIO specification for the NRST input
+
Example:
sx8654@48 {
@@ -12,4 +15,5 @@ Example:
reg = <0x48>;
interrupt-parent = <&gpio6>;
interrupts = <3 IRQ_TYPE_EDGE_FALLING>;
+ reset-gpios = <&gpio4 2 GPIO_ACTIVE_LOW>;
};
--
2.11.0
^ permalink raw reply related
* [PATCH v2 2/8] Input: sx8654 - add reset-gpio support
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
The sx8654 features a NRST input which may be connected to a GPIO.
Therefore add support for hard-resetting the sx8654 via this NRST.
If the reset-gpio property is provided the sx8654 is resetted via NRST
instead of the soft-reset via I2C.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
drivers/input/touchscreen/sx8654.c | 40 +++++++++++++++++++++++++++++++++++---
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index ed29db3ec731..238f56b1581b 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -33,6 +33,8 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/gpio/consumer.h>
+#include <linux/delay.h>
/* register addresses */
#define I2C_REG_TOUCH0 0x00
@@ -74,6 +76,7 @@
struct sx8654 {
struct input_dev *input;
struct i2c_client *client;
+ struct gpio_desc *gpio_reset;
};
static irqreturn_t sx8654_irq(int irq, void *handle)
@@ -124,6 +127,27 @@ static irqreturn_t sx8654_irq(int irq, void *handle)
return IRQ_HANDLED;
}
+static int sx8654_reset(struct sx8654 *ts)
+{
+ int err;
+
+ if (ts->gpio_reset) {
+ gpiod_set_value_cansleep(ts->gpio_reset, 1);
+ udelay(2); /* Tpulse > 1µs */
+ gpiod_set_value_cansleep(ts->gpio_reset, 0);
+
+ return 0;
+ }
+
+ dev_dbg(&ts->client->dev, "NRST unavailable, try softreset\n");
+ err = i2c_smbus_write_byte_data(ts->client, I2C_REG_SOFTRESET,
+ SOFTRESET_VALUE);
+ if (err)
+ return err;
+ else
+ return 0;
+}
+
static int sx8654_open(struct input_dev *dev)
{
struct sx8654 *sx8654 = input_get_drvdata(dev);
@@ -186,6 +210,17 @@ static int sx8654_probe(struct i2c_client *client,
if (!sx8654)
return -ENOMEM;
+ sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(sx8654->gpio_reset)) {
+ error = PTR_ERR(sx8654->gpio_reset);
+ if (error != -EPROBE_DEFER)
+ dev_err(&client->dev, "unable to get reset-gpio: %d\n",
+ error);
+ return error;
+ }
+ dev_dbg(&client->dev, "got GPIO reset pin\n");
+
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
@@ -206,10 +241,9 @@ static int sx8654_probe(struct i2c_client *client,
input_set_drvdata(sx8654->input, sx8654);
- error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
- SOFTRESET_VALUE);
+ error = sx8654_reset(sx8654);
if (error) {
- dev_err(&client->dev, "writing softreset value failed");
+ dev_err(&client->dev, "reset failed");
return error;
}
--
2.11.0
^ permalink raw reply related
* [PATCH v2 3/8] dt-bindings: input: touchscreen: sx8654: add compatible models
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
As the sx865[456] share the same datasheet and differ only in the
presence of a "capacitive proximity detection circuit" and a "haptics
motor driver for LRA/ERM" add them to the compatbiles. As the driver
doesn't implement these features it should be no problem.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
Documentation/devicetree/bindings/input/touchscreen/sx8654.txt | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
index ca521d8f7d65..a538678424dd 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
@@ -1,7 +1,10 @@
* Semtech SX8654 I2C Touchscreen Controller
Required properties:
-- compatible: must be "semtech,sx8654"
+- compatible: must be one of the following, depending on the model:
+ "semtech,sx8654"
+ "semtech,sx8655"
+ "semtech,sx8656"
- reg: i2c slave address
- interrupts: touch controller interrupt
--
2.11.0
^ permalink raw reply related
* [PATCH v2 4/8] Input: sx8654 - add sx8655 and sx8656 to compatibles
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
As the sx865[456] share the same datasheet and differ only in the
presence of a "capacitive proximity detection circuit" and a "haptics
motor driver for LRA/ERM" add them to the compatbiles. As the driver
doesn't implement these features it should be no problem.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
drivers/input/touchscreen/sx8654.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index 238f56b1581b..afa4da138fe9 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -293,6 +293,8 @@ static int sx8654_probe(struct i2c_client *client,
#ifdef CONFIG_OF
static const struct of_device_id sx8654_of_match[] = {
{ .compatible = "semtech,sx8654", },
+ { .compatible = "semtech,sx8655", },
+ { .compatible = "semtech,sx8656", },
{ },
};
MODULE_DEVICE_TABLE(of, sx8654_of_match);
@@ -300,6 +302,8 @@ MODULE_DEVICE_TABLE(of, sx8654_of_match);
static const struct i2c_device_id sx8654_id_table[] = {
{ "semtech_sx8654", 0 },
+ { "semtech_sx8655", 0 },
+ { "semtech_sx8656", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
--
2.11.0
^ permalink raw reply related
* [PATCH v2 5/8] dt-bindings: input: touchscreen: sx8654: add sx8650 to comatibles
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
As the sx8650 is quite similar to the sx8654 support for it will be
added in the driver. Therefore add it to the compatibles.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
Documentation/devicetree/bindings/input/touchscreen/sx8654.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
index a538678424dd..0ebe6dd043c7 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/sx8654.txt
@@ -2,6 +2,7 @@
Required properties:
- compatible: must be one of the following, depending on the model:
+ "semtech,sx8650"
"semtech,sx8654"
"semtech,sx8655"
"semtech,sx8656"
--
2.11.0
^ permalink raw reply related
* [PATCH v2 6/8] Input: sx8654 - add sx8650 support
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
The sx8654 and sx8650 are quite similar, therefore add support for the
sx8650 within the sx8654 driver.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
drivers/input/touchscreen/sx8654.c | 193 +++++++++++++++++++++++++++++++++----
1 file changed, 173 insertions(+), 20 deletions(-)
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index afa4da138fe9..4939863efbef 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -29,7 +29,7 @@
#include <linux/input.h>
#include <linux/module.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -44,9 +44,11 @@
#define I2C_REG_IRQSRC 0x23
#define I2C_REG_SOFTRESET 0x3f
+#define I2C_REG_SX8650_STAT 0x05
+#define SX8650_STAT_CONVIRQ 0x80
+
/* commands */
#define CMD_READ_REGISTER 0x40
-#define CMD_MANUAL 0xc0
#define CMD_PENTRG 0xe0
/* value for I2C_REG_SOFTRESET */
@@ -58,6 +60,7 @@
/* bits for RegTouch1 */
#define CONDIRQ 0x20
+#define RPDNT_100K 0x00
#define FILT_7SA 0x03
/* bits for I2C_REG_CHANMASK */
@@ -71,14 +74,122 @@
/* power delay: lower nibble of CTRL0 register */
#define POWDLY_1_1MS 0x0b
+/* for sx8650, as we have no pen release IRQ there: timeout in ns following the
+ * last PENIRQ after which we assume the pen is lifted.
+ */
+#define SX8650_PENIRQ_TIMEOUT msecs_to_jiffies(10)
+
#define MAX_12BIT ((1 << 12) - 1)
+#define MAX_I2C_READ_LEN 10 /* see datasheet section 5.1.5 */
+
+/* channel definition */
+#define CH_X 0x00
+#define CH_Y 0x01
+
+struct sx865x_data {
+ u8 cmd_manual;
+ u8 chan_mask;
+ u8 has_irq_penrelease;
+ u8 has_reg_irqmask;
+ irq_handler_t irqh;
+};
struct sx8654 {
struct input_dev *input;
struct i2c_client *client;
struct gpio_desc *gpio_reset;
+
+ spinlock_t lock; /* for input reporting from irq/timer */
+ struct timer_list timer;
+
+ const struct sx865x_data *data;
};
+static inline void sx865x_penrelease(struct sx8654 *ts)
+{
+ struct input_dev *input_dev = ts->input;
+
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_sync(input_dev);
+}
+
+static void sx865x_penrelease_timer_handler(struct timer_list *t)
+{
+ struct sx8654 *ts = from_timer(ts, t, timer);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+ sx865x_penrelease(ts);
+ spin_unlock_irqrestore(&ts->lock, flags);
+ dev_dbg(&ts->client->dev, "penrelease by timer\n");
+}
+
+static irqreturn_t sx8650_irq(int irq, void *handle)
+{
+ struct sx8654 *ts = handle;
+ struct device *dev = &ts->client->dev;
+ int len, i;
+ unsigned long flags;
+ u8 stat;
+ u16 x, y;
+ u8 data[MAX_I2C_READ_LEN];
+ u16 ch;
+ u16 chdata;
+ u8 readlen = hweight32(ts->data->chan_mask) * 2;
+
+ stat = i2c_smbus_read_byte_data(ts->client, CMD_READ_REGISTER
+ | I2C_REG_SX8650_STAT);
+
+ if (!(stat & SX8650_STAT_CONVIRQ)) {
+ dev_dbg(dev, "%s ignore stat [0x%02x]", __func__, stat);
+ return IRQ_HANDLED;
+ }
+
+ len = i2c_master_recv(ts->client, data, readlen);
+ if (len != readlen) {
+ dev_dbg(dev, "ignore short recv (%d)\n", len);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ x = 0;
+ y = 0;
+ for (i = 0; (i + 1) < len; i++) {
+ chdata = data[i] << 8;
+ i++;
+ chdata += data[i];
+
+ if (unlikely(chdata == 0xFFFF)) {
+ dev_dbg(dev, "invalid qualified data @ %d\n", i);
+ continue;
+ } else if (unlikely(chdata & 0x8000)) {
+ dev_warn(dev, "hibit @ %d [0x%04x]\n", i, chdata);
+ continue;
+ }
+
+ ch = chdata >> 12;
+ if (ch == CH_X)
+ x = chdata & MAX_12BIT;
+ else if (ch == CH_Y)
+ y = chdata & MAX_12BIT;
+ else
+ dev_warn(dev, "unknown channel %d [0x%04x]\n", ch,
+ chdata);
+ }
+
+ input_report_abs(ts->input, ABS_X, x);
+ input_report_abs(ts->input, ABS_Y, y);
+ input_report_key(ts->input, BTN_TOUCH, 1);
+ input_sync(ts->input);
+ dev_dbg(dev, "point(%4d,%4d)\n", x, y);
+
+ mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT);
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
static irqreturn_t sx8654_irq(int irq, void *handle)
{
struct sx8654 *sx8654 = handle;
@@ -127,6 +238,22 @@ static irqreturn_t sx8654_irq(int irq, void *handle)
return IRQ_HANDLED;
}
+static const struct sx865x_data sx8650_data = {
+ .cmd_manual = 0xb0,
+ .has_irq_penrelease = 0,
+ .has_reg_irqmask = 0,
+ .chan_mask = (CONV_X | CONV_Y),
+ .irqh = sx8650_irq,
+};
+
+static const struct sx865x_data sx8654_data = {
+ .cmd_manual = 0xc0,
+ .has_irq_penrelease = 1,
+ .has_reg_irqmask = 1,
+ .chan_mask = (CONV_X | CONV_Y),
+ .irqh = sx8654_irq,
+};
+
static int sx8654_reset(struct sx8654 *ts)
{
int err;
@@ -182,13 +309,13 @@ static void sx8654_close(struct input_dev *dev)
disable_irq(client->irq);
/* enable manual mode mode */
- error = i2c_smbus_write_byte(client, CMD_MANUAL);
+ error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
if (error) {
dev_err(&client->dev, "writing command CMD_MANUAL failed");
return;
}
- error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
+ error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, RATE_MANUAL);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
return;
@@ -221,6 +348,20 @@ static int sx8654_probe(struct i2c_client *client,
}
dev_dbg(&client->dev, "got GPIO reset pin\n");
+ sx8654->data = of_device_get_match_data(&client->dev);
+ if (!sx8654->data)
+ sx8654->data = (const struct sx865x_data *)id->driver_data;
+ if (!sx8654->data) {
+ dev_err(&client->dev, "invalid or missing device data\n");
+ return -EINVAL;
+ }
+
+ if (!sx8654->data->has_irq_penrelease) {
+ dev_dbg(&client->dev, "use timer for penrelease\n");
+ timer_setup(&sx8654->timer, sx865x_penrelease_timer_handler, 0);
+ spin_lock_init(&sx8654->lock);
+ }
+
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
@@ -248,29 +389,31 @@ static int sx8654_probe(struct i2c_client *client,
}
error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
- CONV_X | CONV_Y);
+ sx8654->data->chan_mask);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
return error;
}
- error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
- IRQ_PENTOUCH_TOUCHCONVDONE |
- IRQ_PENRELEASE);
- if (error) {
- dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
- return error;
+ if (sx8654->data->has_reg_irqmask) {
+ error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
+ IRQ_PENTOUCH_TOUCHCONVDONE |
+ IRQ_PENRELEASE);
+ if (error) {
+ dev_err(&client->dev, "writing I2C_REG_IRQMASK failed");
+ return error;
+ }
}
error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
- CONDIRQ | FILT_7SA);
+ CONDIRQ | RPDNT_100K | FILT_7SA);
if (error) {
dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
return error;
}
error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, sx8654_irq,
+ NULL, sx8654->data->irqh,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, sx8654);
if (error) {
@@ -292,18 +435,28 @@ static int sx8654_probe(struct i2c_client *client,
#ifdef CONFIG_OF
static const struct of_device_id sx8654_of_match[] = {
- { .compatible = "semtech,sx8654", },
- { .compatible = "semtech,sx8655", },
- { .compatible = "semtech,sx8656", },
- { },
+ {
+ .compatible = "semtech,sx8650",
+ .data = &sx8650_data,
+ }, {
+ .compatible = "semtech,sx8654",
+ .data = &sx8654_data,
+ }, {
+ .compatible = "semtech,sx8655",
+ .data = &sx8654_data,
+ }, {
+ .compatible = "semtech,sx8656",
+ .data = &sx8654_data,
+ }, {},
};
MODULE_DEVICE_TABLE(of, sx8654_of_match);
#endif
static const struct i2c_device_id sx8654_id_table[] = {
- { "semtech_sx8654", 0 },
- { "semtech_sx8655", 0 },
- { "semtech_sx8656", 0 },
+ { .name = "semtech_sx8650", .driver_data = (long)&sx8650_data },
+ { .name = "semtech_sx8654", .driver_data = (long)&sx8654_data },
+ { .name = "semtech_sx8655", .driver_data = (long)&sx8654_data },
+ { .name = "semtech_sx8656", .driver_data = (long)&sx8654_data },
{ },
};
MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
--
2.11.0
^ permalink raw reply related
* [PATCH v2 7/8] Input: sx8654 - use common of_touchscreen functions
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
of_touchscreen.c provides a common interface for a axis invertion and
swapping of touchscreens. Therefore use it in the sx8654 driver.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
drivers/input/touchscreen/sx8654.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index 4939863efbef..b7b263ed52af 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -35,6 +35,7 @@
#include <linux/irq.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
+#include <linux/input/touchscreen.h>
/* register addresses */
#define I2C_REG_TOUCH0 0x00
@@ -101,6 +102,7 @@ struct sx8654 {
spinlock_t lock; /* for input reporting from irq/timer */
struct timer_list timer;
+ struct touchscreen_properties props;
const struct sx865x_data *data;
};
@@ -178,8 +180,7 @@ static irqreturn_t sx8650_irq(int irq, void *handle)
chdata);
}
- input_report_abs(ts->input, ABS_X, x);
- input_report_abs(ts->input, ABS_Y, y);
+ touchscreen_report_pos(ts->input, &ts->props, x, y, false);
input_report_key(ts->input, BTN_TOUCH, 1);
input_sync(ts->input);
dev_dbg(dev, "point(%4d,%4d)\n", x, y);
@@ -226,8 +227,8 @@ static irqreturn_t sx8654_irq(int irq, void *handle)
x = ((data[0] & 0xf) << 8) | (data[1]);
y = ((data[2] & 0xf) << 8) | (data[3]);
- input_report_abs(sx8654->input, ABS_X, x);
- input_report_abs(sx8654->input, ABS_Y, y);
+ touchscreen_report_pos(sx8654->input, &sx8654->props, x, y,
+ false);
input_report_key(sx8654->input, BTN_TOUCH, 1);
input_sync(sx8654->input);
@@ -377,6 +378,8 @@ static int sx8654_probe(struct i2c_client *client,
input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
+ touchscreen_parse_properties(input, false, &sx8654->props);
+
sx8654->client = client;
sx8654->input = input;
--
2.11.0
^ permalink raw reply related
* [PATCH v2 8/8] Input: sx8654 - convert #defined flags to BIT(x)
From: Richard Leitner @ 2018-10-17 12:51 UTC (permalink / raw)
To: dmitry.torokhov, robh+dt, mark.rutland
Cc: linux-input, devicetree, linux-kernel, Richard Leitner
In-Reply-To: <20181017125116.20077-1-richard.leitner@skidata.com>
Some of the #defined register values are one-bit flags. Convert them to
use the BIT(x) macro instead of 1 byte hexadecimal values. This improves
readability and clarifies the intent.
Signed-off-by: Richard Leitner <richard.leitner@skidata.com>
---
drivers/input/touchscreen/sx8654.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index b7b263ed52af..3746ea855f94 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -36,6 +36,7 @@
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/input/touchscreen.h>
+#include <linux/bitops.h>
/* register addresses */
#define I2C_REG_TOUCH0 0x00
@@ -46,7 +47,7 @@
#define I2C_REG_SOFTRESET 0x3f
#define I2C_REG_SX8650_STAT 0x05
-#define SX8650_STAT_CONVIRQ 0x80
+#define SX8650_STAT_CONVIRQ BIT(7)
/* commands */
#define CMD_READ_REGISTER 0x40
@@ -56,8 +57,8 @@
#define SOFTRESET_VALUE 0xde
/* bits for I2C_REG_IRQSRC */
-#define IRQ_PENTOUCH_TOUCHCONVDONE 0x08
-#define IRQ_PENRELEASE 0x04
+#define IRQ_PENTOUCH_TOUCHCONVDONE BIT(7)
+#define IRQ_PENRELEASE BIT(6)
/* bits for RegTouch1 */
#define CONDIRQ 0x20
@@ -65,8 +66,8 @@
#define FILT_7SA 0x03
/* bits for I2C_REG_CHANMASK */
-#define CONV_X 0x80
-#define CONV_Y 0x40
+#define CONV_X BIT(7)
+#define CONV_Y BIT(6)
/* coordinates rate: higher nibble of CTRL0 register */
#define RATE_MANUAL 0x00
--
2.11.0
^ permalink raw reply related
* Re: WARNING: kmalloc bug in input_mt_init_slots
From: Christopher Lameter @ 2018-10-17 15:35 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Matthew Wilcox, Dmitry Vyukov, syzbot+87829a10073277282ad1,
Pekka Enberg, linux-input@vger.kernel.org, lkml, Henrik Rydberg,
syzkaller-bugs, Linux-MM
In-Reply-To: <20181017000955.GG230131@dtor-ws>
On Tue, 16 Oct 2018, Dmitry Torokhov wrote:
> On Thu, Sep 27, 2018 at 07:35:37AM -0700, Matthew Wilcox wrote:
> > On Mon, Sep 24, 2018 at 11:41:58AM -0700, Dmitry Torokhov wrote:
> > > > How large is the allocation? AFACIT nRequests larger than KMALLOC_MAX_SIZE
> > > > are larger than the maximum allowed by the page allocator. Thus the warning
> > > > and the NULL return.
> > >
> > > The size in this particular case is being derived from a value passed
> > > from userspace. Input core does not care about any limits on size of
> > > memory kmalloc() can support and is perfectly happy with getting NULL
> > > and telling userspace to go away with their silly requests by returning
> > > -ENOMEM.
> > >
> > > For the record: I definitely do not want to pre-sanitize size neither in
> > > uinput nor in input core.
> >
> > Probably should be using kvzalloc then.
>
> No. No sane input device can track so many contacts so we need to use
> kvzalloc(). Failing to allocate memory is proper response here.
What is a "contact" here? Are we talking about SG segments?
^ permalink raw reply
* Re: WARNING: kmalloc bug in input_mt_init_slots
From: Dmitry Torokhov @ 2018-10-17 15:43 UTC (permalink / raw)
To: Christopher Lameter
Cc: Matthew Wilcox, Dmitry Vyukov, syzbot+87829a10073277282ad1,
Pekka Enberg, linux-input@vger.kernel.org, lkml, Henrik Rydberg,
syzkaller-bugs, Linux-MM
In-Reply-To: <0100016682aaae79-d1382d3d-83f8-4972-b4b9-6220367f4f65-000000@email.amazonses.com>
On October 17, 2018 8:35:15 AM PDT, Christopher Lameter <cl@linux.com> wrote:
>On Tue, 16 Oct 2018, Dmitry Torokhov wrote:
>
>> On Thu, Sep 27, 2018 at 07:35:37AM -0700, Matthew Wilcox wrote:
>> > On Mon, Sep 24, 2018 at 11:41:58AM -0700, Dmitry Torokhov wrote:
>> > > > How large is the allocation? AFACIT nRequests larger than
>KMALLOC_MAX_SIZE
>> > > > are larger than the maximum allowed by the page allocator. Thus
>the warning
>> > > > and the NULL return.
>> > >
>> > > The size in this particular case is being derived from a value
>passed
>> > > from userspace. Input core does not care about any limits on size
>of
>> > > memory kmalloc() can support and is perfectly happy with getting
>NULL
>> > > and telling userspace to go away with their silly requests by
>returning
>> > > -ENOMEM.
>> > >
>> > > For the record: I definitely do not want to pre-sanitize size
>neither in
>> > > uinput nor in input core.
>> >
>> > Probably should be using kvzalloc then.
>>
>> No. No sane input device can track so many contacts so we need to use
>> kvzalloc(). Failing to allocate memory is proper response here.
>
>What is a "contact" here? Are we talking about SG segments?
No, we are talking about maximum number of fingers a person can have. Devices don't usually track more than 10 distinct contacts on the touch surface at a time.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: WARNING: kmalloc bug in input_mt_init_slots
From: Christopher Lameter @ 2018-10-17 15:53 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Matthew Wilcox, Dmitry Vyukov, syzbot+87829a10073277282ad1,
Pekka Enberg, linux-input@vger.kernel.org, lkml, Henrik Rydberg,
syzkaller-bugs, Linux-MM
In-Reply-To: <CE3D3608-F320-4DAB-8BEB-3EFDDB54F97E@gmail.com>
On Wed, 17 Oct 2018, Dmitry Torokhov wrote:
> >What is a "contact" here? Are we talking about SG segments?
>
> No, we are talking about maximum number of fingers a person can have. Devices don't usually track more than 10 distinct contacts on the touch surface at a time.
Ohh... Way off my usual contexts of development. Sorry.
Ok you have my blessing.
^ permalink raw reply
* Re: [PATCH] HID: quirks: fix support for Apple Magic Keyboards
From: Benjamin Tissoires @ 2018-10-17 16:49 UTC (permalink / raw)
To: ncopa, linux stable; +Cc: open list:HID CORE LAYER, Jiri Kosina, seobrien
In-Reply-To: <20181017175515.798b2316@ncopa-desktop.copa.dup.pw>
On Wed, Oct 17, 2018 at 5:55 PM Natanael Copa <ncopa@alpinelinux.org> wrote:
>
> On Wed, 17 Oct 2018 16:59:15 +0200
> Benjamin Tissoires <benjamin.tissoires@redhat.com> wrote:
>
> > Hi Natanael,
> >
> > On Wed, Oct 17, 2018 at 4:52 PM Natanael Copa <ncopa@alpinelinux.org> wrote:
> > >
> > > Commit ee3454924370 ("HID: add support for Apple Magic Keyboards") added
> > > support for the Magic Keyboard over Bluetooth, but did not add the
> > > BT_VENDOR_ID_APPLE to hid-quirks. Fix this so hid-apple driver is used
> > > over hid-generic.
> > >
> > > This fixes the Fn key, which does not work at all with hid-generic.
> > >
> > > Fixes: ee3454924370 ("HID: add support for Apple Magic Keyboards")
> > > Bugzilla-id: https://bugzilla.kernel.org/show_bug.cgi?id=99881
> > > Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
> > > ---
> > > This should be backported to stable too.
> > >
> > > drivers/hid/hid-quirks.c | 3 +++
> > > 1 file changed, 3 insertions(+)
> > >
> > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> > > index 249d49b6b16c..a3b3aecf8628 100644
> > > --- a/drivers/hid/hid-quirks.c
> > > +++ b/drivers/hid/hid-quirks.c
> > > @@ -270,6 +270,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
> > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
> > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
> > > { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
> > > + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
> > > + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI) },
> > > + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI) },
> >
> > NACK, this should not be required with kernels v4.17+ IIRC.
> >
> > If it doesn't work on a recent kernel, please raise the issue, but I
> > am actually chasing down the new inclusions of these when we add new
> > device support.
>
> Fair enough. I think it may be needed for 4.14.y kernels though, to fix
> commit b6cc0ba2cbf4 (HID: add support for Apple Magic Keyboards).
>
> Fn key did not work without this patch on 4.14.76 for me.
Right, b6cc0ba2cbf4 has been added to 4.14.75 and is not working
because tweaking hid_have_special_driver[] is not required in current
kernels anymore.
@stable folks, would it be possible to take this patch in the v4.9 and
v4.14 trees? It can't go into Linus' tree, but I'd be glad to give my
Acked-by for a stable backport.
>
> > There is even a high chance that we remove the list entirely as this
> > would tremendously help the distributions to just have to ship
> > hid-generic in the initramfs instead of a bunch of random hid drivers.
>
> I doubt that distros will want Bluetooth keyboards there though. (which
> this is about)
I was talking more generally, killing this list of devices, as some
are keyboard and useful, and some are not needed as you say. But the
point is that distro folks won't have to decide which module to ship:
only hid-generic will be sufficient.
Cheers,
Benjamin
>
> > By the way, if the driver is not autoloaded by udev, it is a problem
> > in udev likely.
> >
> > Cheers,
> > Benjamin
> >
> > > { HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
> > > USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
> > > { HID_USB_DEVICE(USB_VENDOR_ID_APPLE,
> > > USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, #endif --
> > > 2.19.1
> > >
>
^ permalink raw reply
* Re: [PATCH] HID: quirks: fix support for Apple Magic Keyboards
From: Greg KH @ 2018-10-17 16:55 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: ncopa, linux stable, open list:HID CORE LAYER, Jiri Kosina,
seobrien
In-Reply-To: <CAO-hwJ+6Ksm6ZC85yUg86WEvfCvrBQ61OELepydx7ELYKGaqyQ@mail.gmail.com>
On Wed, Oct 17, 2018 at 06:49:16PM +0200, Benjamin Tissoires wrote:
> On Wed, Oct 17, 2018 at 5:55 PM Natanael Copa <ncopa@alpinelinux.org> wrote:
> >
> > On Wed, 17 Oct 2018 16:59:15 +0200
> > Benjamin Tissoires <benjamin.tissoires@redhat.com> wrote:
> >
> > > Hi Natanael,
> > >
> > > On Wed, Oct 17, 2018 at 4:52 PM Natanael Copa <ncopa@alpinelinux.org> wrote:
> > > >
> > > > Commit ee3454924370 ("HID: add support for Apple Magic Keyboards") added
> > > > support for the Magic Keyboard over Bluetooth, but did not add the
> > > > BT_VENDOR_ID_APPLE to hid-quirks. Fix this so hid-apple driver is used
> > > > over hid-generic.
> > > >
> > > > This fixes the Fn key, which does not work at all with hid-generic.
> > > >
> > > > Fixes: ee3454924370 ("HID: add support for Apple Magic Keyboards")
> > > > Bugzilla-id: https://bugzilla.kernel.org/show_bug.cgi?id=99881
> > > > Signed-off-by: Natanael Copa <ncopa@alpinelinux.org>
> > > > ---
> > > > This should be backported to stable too.
> > > >
> > > > drivers/hid/hid-quirks.c | 3 +++
> > > > 1 file changed, 3 insertions(+)
> > > >
> > > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
> > > > index 249d49b6b16c..a3b3aecf8628 100644
> > > > --- a/drivers/hid/hid-quirks.c
> > > > +++ b/drivers/hid/hid-quirks.c
> > > > @@ -270,6 +270,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
> > > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
> > > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
> > > > { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
> > > > + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
> > > > + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI) },
> > > > + { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_ANSI) },
> > >
> > > NACK, this should not be required with kernels v4.17+ IIRC.
> > >
> > > If it doesn't work on a recent kernel, please raise the issue, but I
> > > am actually chasing down the new inclusions of these when we add new
> > > device support.
> >
> > Fair enough. I think it may be needed for 4.14.y kernels though, to fix
> > commit b6cc0ba2cbf4 (HID: add support for Apple Magic Keyboards).
> >
> > Fn key did not work without this patch on 4.14.76 for me.
>
> Right, b6cc0ba2cbf4 has been added to 4.14.75 and is not working
> because tweaking hid_have_special_driver[] is not required in current
> kernels anymore.
>
> @stable folks, would it be possible to take this patch in the v4.9 and
> v4.14 trees? It can't go into Linus' tree, but I'd be glad to give my
> Acked-by for a stable backport.
Sure, if you resend it in a format that I can apply it in, with the text
saying why this is not applicable to newer kernel versions.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: add more optional properties for elan_i2c touchpads
From: Rob Herring @ 2018-10-17 20:15 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, KT Liao, linux-input, linux-kernel, devicetree
In-Reply-To: <20181012142413.26107-4-benjamin.tissoires@redhat.com>
On Fri, Oct 12, 2018 at 04:24:11PM +0200, Benjamin Tissoires wrote:
> Some new touchpads IC are connected through PS/2 and I2C. On some of these
> new IC, the I2C part doesn't have all of the information available.
> We need to be able to forward the touchpad parameters from PS/2 and
> thus, we need those new optional properties.
>
> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1628715
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> ---
> Documentation/devicetree/bindings/input/elan_i2c.txt | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
> index 797607460735..ace6bcb0b4eb 100644
> --- a/Documentation/devicetree/bindings/input/elan_i2c.txt
> +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
> @@ -13,6 +13,14 @@ Optional properties:
> pinctrl binding [1]).
> - vcc-supply: a phandle for the regulator supplying 3.3V power.
> - elan,trackpoint: touchpad can support a trackpoint (boolean)
> +- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
> +- elan,max_x: the maximum reported value on the X axis
> +- elan,max_y: the maximum reported value on the Y axis
> +- elan,min_x: the minimum reported value on the X axis
> +- elan,min_y: the minimum reported value on the Y axis
> +- elan,x_res: the resolution of the X axis (in units per mm)
> +- elan,y_res: the resolution of the Y axis (in units per mm)
> +- elan,width: max reported width of a blob
Can't we use standard touchscreen properties here? (Yes, I get this is a
touchpad, not touchscreen).
Rob
^ permalink raw reply
* Re: [PATCH] Input: pm8941-pwrkey - Add pms405 pwrkey support
From: Vinod @ 2018-10-18 5:24 UTC (permalink / raw)
To: Bjorn Andersson
Cc: Dmitry Torokhov, Rob Herring, Mark Rutland, linux-input,
devicetree, linux-kernel
In-Reply-To: <20180920014928.15422-1-bjorn.andersson@linaro.org>
On 19-09-18, 18:49, Bjorn Andersson wrote:
> From: Vinod Koul <vkoul@kernel.org>
>
> Update the binding and driver for pms405 pwrkey.
Rob, Dmitry
Gentle reminder for this patch...
> Signed-off-by: Vinod Koul <vkoul@kernel.org>
> Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
> ---
> Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt | 1 +
> drivers/input/misc/pm8941-pwrkey.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
> index 34ab5763f494..736fba3bad54 100644
> --- a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
> +++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
> @@ -8,6 +8,7 @@ PROPERTIES
> Definition: must be one of:
> "qcom,pm8941-pwrkey"
> "qcom,pm8941-resin"
> + "qcom,pms405-pwrkey"
>
> - reg:
> Usage: required
> diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
> index 48153e0ca19a..fccf63263c1c 100644
> --- a/drivers/input/misc/pm8941-pwrkey.c
> +++ b/drivers/input/misc/pm8941-pwrkey.c
> @@ -317,6 +317,7 @@ static const struct pm8941_data resin_data = {
> static const struct of_device_id pm8941_pwr_key_id_table[] = {
> { .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data },
> { .compatible = "qcom,pm8941-resin", .data = &resin_data },
> + { .compatible = "qcom,pms405-pwrkey", .data = &pwrkey_data },
> { }
> };
> MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
> --
> 2.18.0
--
~Vinod
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: add more optional properties for elan_i2c touchpads
From: Benjamin Tissoires @ 2018-10-18 8:10 UTC (permalink / raw)
To: robh, Hans de Goede
Cc: Dmitry Torokhov, 廖崇榮,
open list:HID CORE LAYER, lkml, devicetree
In-Reply-To: <20181017201522.GA26525@bogus>
On Wed, Oct 17, 2018 at 10:15 PM Rob Herring <robh@kernel.org> wrote:
>
> On Fri, Oct 12, 2018 at 04:24:11PM +0200, Benjamin Tissoires wrote:
> > Some new touchpads IC are connected through PS/2 and I2C. On some of these
> > new IC, the I2C part doesn't have all of the information available.
> > We need to be able to forward the touchpad parameters from PS/2 and
> > thus, we need those new optional properties.
> >
> > Link: https://bugzilla.redhat.com/show_bug.cgi?id=1628715
> > Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> > ---
> > Documentation/devicetree/bindings/input/elan_i2c.txt | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
> > index 797607460735..ace6bcb0b4eb 100644
> > --- a/Documentation/devicetree/bindings/input/elan_i2c.txt
> > +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
> > @@ -13,6 +13,14 @@ Optional properties:
> > pinctrl binding [1]).
> > - vcc-supply: a phandle for the regulator supplying 3.3V power.
> > - elan,trackpoint: touchpad can support a trackpoint (boolean)
> > +- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
>
> > +- elan,max_x: the maximum reported value on the X axis
> > +- elan,max_y: the maximum reported value on the Y axis
> > +- elan,min_x: the minimum reported value on the X axis
> > +- elan,min_y: the minimum reported value on the Y axis
> > +- elan,x_res: the resolution of the X axis (in units per mm)
> > +- elan,y_res: the resolution of the Y axis (in units per mm)
> > +- elan,width: max reported width of a blob
>
> Can't we use standard touchscreen properties here? (Yes, I get this is a
> touchpad, not touchscreen).
Hey Rob,
Well, there is that (it's a touchpad driver) and we can't also really
use the of_touchscreen.c implementation.
If both concerns are not an issue, we can then move the [min/max/res]
properties to the touchscreen ones.
Regarding 'elan,width', this is something missing from the standard ts
properties, and AFAICT, this controls the maximum reported
width/height of a touch.
I should probably rename them to max_width, max_height.
Hans, do you think we should add such properties to of_touchscreen.c
too? (the width/height ones)
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: add more optional properties for elan_i2c touchpads
From: Hans de Goede @ 2018-10-18 8:39 UTC (permalink / raw)
To: Benjamin Tissoires, robh
Cc: Dmitry Torokhov, 廖崇榮,
open list:HID CORE LAYER, lkml, devicetree
In-Reply-To: <CAO-hwJ+z6YdnLdbzeh-7f99cBBjHfbLKLzKo-fQQaC_W8bt_Uw@mail.gmail.com>
Hi,
On 18-10-18 10:10, Benjamin Tissoires wrote:
> On Wed, Oct 17, 2018 at 10:15 PM Rob Herring <robh@kernel.org> wrote:
>>
>> On Fri, Oct 12, 2018 at 04:24:11PM +0200, Benjamin Tissoires wrote:
>>> Some new touchpads IC are connected through PS/2 and I2C. On some of these
>>> new IC, the I2C part doesn't have all of the information available.
>>> We need to be able to forward the touchpad parameters from PS/2 and
>>> thus, we need those new optional properties.
>>>
>>> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1628715
>>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>>> ---
>>> Documentation/devicetree/bindings/input/elan_i2c.txt | 8 ++++++++
>>> 1 file changed, 8 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
>>> index 797607460735..ace6bcb0b4eb 100644
>>> --- a/Documentation/devicetree/bindings/input/elan_i2c.txt
>>> +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
>>> @@ -13,6 +13,14 @@ Optional properties:
>>> pinctrl binding [1]).
>>> - vcc-supply: a phandle for the regulator supplying 3.3V power.
>>> - elan,trackpoint: touchpad can support a trackpoint (boolean)
>>> +- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
>>
>>> +- elan,max_x: the maximum reported value on the X axis
>>> +- elan,max_y: the maximum reported value on the Y axis
>>> +- elan,min_x: the minimum reported value on the X axis
>>> +- elan,min_y: the minimum reported value on the Y axis
>>> +- elan,x_res: the resolution of the X axis (in units per mm)
>>> +- elan,y_res: the resolution of the Y axis (in units per mm)
>>> +- elan,width: max reported width of a blob
>>
>> Can't we use standard touchscreen properties here? (Yes, I get this is a
>> touchpad, not touchscreen).
>
> Hey Rob,
>
> Well, there is that (it's a touchpad driver) and we can't also really
> use the of_touchscreen.c implementation.
> If both concerns are not an issue, we can then move the [min/max/res]
> properties to the touchscreen ones.
>
> Regarding 'elan,width', this is something missing from the standard ts
> properties, and AFAICT, this controls the maximum reported
> width/height of a touch.
> I should probably rename them to max_width, max_height.
>
> Hans, do you think we should add such properties to of_touchscreen.c
> too? (the width/height ones)
Are there touchscreens which report finger/touch width / height ? if so
then it probably does make sense. Note that for historical reasons
Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
Also the touchscreen bindings have: touchscreen-x-mm and touchscreen-y-mm
rather then res, which can then be used to calculate the resolution.
Regards,
Hans
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: add more optional properties for elan_i2c touchpads
From: Benjamin Tissoires @ 2018-10-18 8:44 UTC (permalink / raw)
To: Hans de Goede
Cc: robh, Dmitry Torokhov, 廖崇榮,
open list:HID CORE LAYER, lkml, devicetree
In-Reply-To: <1fb98946-a518-d7d7-3bec-8944be95b91c@redhat.com>
On Thu, Oct 18, 2018 at 10:39 AM Hans de Goede <hdegoede@redhat.com> wrote:
>
> Hi,
>
> On 18-10-18 10:10, Benjamin Tissoires wrote:
> > On Wed, Oct 17, 2018 at 10:15 PM Rob Herring <robh@kernel.org> wrote:
> >>
> >> On Fri, Oct 12, 2018 at 04:24:11PM +0200, Benjamin Tissoires wrote:
> >>> Some new touchpads IC are connected through PS/2 and I2C. On some of these
> >>> new IC, the I2C part doesn't have all of the information available.
> >>> We need to be able to forward the touchpad parameters from PS/2 and
> >>> thus, we need those new optional properties.
> >>>
> >>> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1628715
> >>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> >>> ---
> >>> Documentation/devicetree/bindings/input/elan_i2c.txt | 8 ++++++++
> >>> 1 file changed, 8 insertions(+)
> >>>
> >>> diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
> >>> index 797607460735..ace6bcb0b4eb 100644
> >>> --- a/Documentation/devicetree/bindings/input/elan_i2c.txt
> >>> +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
> >>> @@ -13,6 +13,14 @@ Optional properties:
> >>> pinctrl binding [1]).
> >>> - vcc-supply: a phandle for the regulator supplying 3.3V power.
> >>> - elan,trackpoint: touchpad can support a trackpoint (boolean)
> >>> +- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
> >>
> >>> +- elan,max_x: the maximum reported value on the X axis
> >>> +- elan,max_y: the maximum reported value on the Y axis
> >>> +- elan,min_x: the minimum reported value on the X axis
> >>> +- elan,min_y: the minimum reported value on the Y axis
> >>> +- elan,x_res: the resolution of the X axis (in units per mm)
> >>> +- elan,y_res: the resolution of the Y axis (in units per mm)
> >>> +- elan,width: max reported width of a blob
> >>
> >> Can't we use standard touchscreen properties here? (Yes, I get this is a
> >> touchpad, not touchscreen).
> >
> > Hey Rob,
> >
> > Well, there is that (it's a touchpad driver) and we can't also really
> > use the of_touchscreen.c implementation.
> > If both concerns are not an issue, we can then move the [min/max/res]
> > properties to the touchscreen ones.
> >
> > Regarding 'elan,width', this is something missing from the standard ts
> > properties, and AFAICT, this controls the maximum reported
> > width/height of a touch.
> > I should probably rename them to max_width, max_height.
> >
> > Hans, do you think we should add such properties to of_touchscreen.c
> > too? (the width/height ones)
>
> Are there touchscreens which report finger/touch width / height ? if so
> then it probably does make sense.
Well, it's pretty common for hid-multitouch touchscreens to report
such properties (it's a way to indicate the palm). Don't know about
the touchscreens that rely on of_touchscreen though.
> Note that for historical reasons
> Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
Looks like your sentence is not finished here :)
>
> Also the touchscreen bindings have: touchscreen-x-mm and touchscreen-y-mm
> rather then res, which can then be used to calculate the resolution.
>
yeah, that's fine, I would need to convert to mm, then go back to res.
Extra effort, but that's the price to pay.
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH 3/5] dt-bindings: add more optional properties for elan_i2c touchpads
From: Hans de Goede @ 2018-10-18 8:51 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: robh, Dmitry Torokhov, 廖崇榮,
open list:HID CORE LAYER, lkml, devicetree
In-Reply-To: <CAO-hwJKXBvuGLensAQv82SoPh-vrt9UFgoC3_XeTA78EHCOANA@mail.gmail.com>
Hi,
On 18-10-18 10:44, Benjamin Tissoires wrote:
> On Thu, Oct 18, 2018 at 10:39 AM Hans de Goede <hdegoede@redhat.com> wrote:
>>
>> Hi,
>>
>> On 18-10-18 10:10, Benjamin Tissoires wrote:
>>> On Wed, Oct 17, 2018 at 10:15 PM Rob Herring <robh@kernel.org> wrote:
>>>>
>>>> On Fri, Oct 12, 2018 at 04:24:11PM +0200, Benjamin Tissoires wrote:
>>>>> Some new touchpads IC are connected through PS/2 and I2C. On some of these
>>>>> new IC, the I2C part doesn't have all of the information available.
>>>>> We need to be able to forward the touchpad parameters from PS/2 and
>>>>> thus, we need those new optional properties.
>>>>>
>>>>> Link: https://bugzilla.redhat.com/show_bug.cgi?id=1628715
>>>>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>>>>> ---
>>>>> Documentation/devicetree/bindings/input/elan_i2c.txt | 8 ++++++++
>>>>> 1 file changed, 8 insertions(+)
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/input/elan_i2c.txt b/Documentation/devicetree/bindings/input/elan_i2c.txt
>>>>> index 797607460735..ace6bcb0b4eb 100644
>>>>> --- a/Documentation/devicetree/bindings/input/elan_i2c.txt
>>>>> +++ b/Documentation/devicetree/bindings/input/elan_i2c.txt
>>>>> @@ -13,6 +13,14 @@ Optional properties:
>>>>> pinctrl binding [1]).
>>>>> - vcc-supply: a phandle for the regulator supplying 3.3V power.
>>>>> - elan,trackpoint: touchpad can support a trackpoint (boolean)
>>>>> +- elan,clickpad: touchpad is a clickpad (the entire surface is a button)
>>>>
>>>>> +- elan,max_x: the maximum reported value on the X axis
>>>>> +- elan,max_y: the maximum reported value on the Y axis
>>>>> +- elan,min_x: the minimum reported value on the X axis
>>>>> +- elan,min_y: the minimum reported value on the Y axis
>>>>> +- elan,x_res: the resolution of the X axis (in units per mm)
>>>>> +- elan,y_res: the resolution of the Y axis (in units per mm)
>>>>> +- elan,width: max reported width of a blob
>>>>
>>>> Can't we use standard touchscreen properties here? (Yes, I get this is a
>>>> touchpad, not touchscreen).
>>>
>>> Hey Rob,
>>>
>>> Well, there is that (it's a touchpad driver) and we can't also really
>>> use the of_touchscreen.c implementation.
>>> If both concerns are not an issue, we can then move the [min/max/res]
>>> properties to the touchscreen ones.
>>>
>>> Regarding 'elan,width', this is something missing from the standard ts
>>> properties, and AFAICT, this controls the maximum reported
>>> width/height of a touch.
>>> I should probably rename them to max_width, max_height.
>>>
>>> Hans, do you think we should add such properties to of_touchscreen.c
>>> too? (the width/height ones)
>>
>> Are there touchscreens which report finger/touch width / height ? if so
>> then it probably does make sense.
>
> Well, it's pretty common for hid-multitouch touchscreens to report
> such properties (it's a way to indicate the palm). Don't know about
> the touchscreens that rely on of_touchscreen though.
Now that you mention it I think some may also have some sort of
pressure/weight value, but at least for the ones I wrote I do not
think we do anything with it, since the actual meaning of the
field is somewhat vague. This is all IIRC.
>> Note that for historical reasons
>> Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
>
> Looks like your sentence is not finished here :)
I actually deleted it, but not those 2 lines, what I had written there
was that for historical reasons it uses touchscreen-size-x rather then
max-x and that that might be a bit confusing vs max-width, but I could
not come up with something better then max-width, so I deleted my
rambling, but ended up not deleting all of it :)
>> Also the touchscreen bindings have: touchscreen-x-mm and touchscreen-y-mm
>> rather then res, which can then be used to calculate the resolution.
>>
>
> yeah, that's fine, I would need to convert to mm, then go back to res.
> Extra effort, but that's the price to pay.
Ack.
Regards,
Hans
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox