* [PATCH 2/2] HID: wacom - Update maximum X/Y accounding to outbound offset
From: Ping Cheng @ 2014-12-05 2:25 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, Ping Cheng
Defined outbound offset for DTU and Cintiq. But didn't update
the relevant maximum values. Oops...
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
drivers/hid/wacom_wac.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index b65e0d7..7b7a61a 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -2685,11 +2685,11 @@ static const struct wacom_features wacom_features_0x317 =
INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xF4 =
- { "Wacom Cintiq 24HD", 104280, 65400, 2047, 63,
+ { "Wacom Cintiq 24HD", 104080, 65200, 2047, 63,
WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xF8 =
- { "Wacom Cintiq 24HD touch", 104280, 65400, 2047, 63, /* Pen */
+ { "Wacom Cintiq 24HD touch", 104080, 65200, 2047, 63, /* Pen */
WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 };
@@ -2707,7 +2707,7 @@ static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", 53020, 33440, 1023, 63,
WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0x304 =
- { "Wacom Cintiq 13HD", 59352, 33648, 1023, 63,
+ { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63,
WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xC7 =
@@ -2721,7 +2721,7 @@ static const struct wacom_features wacom_features_0xF0 =
{ "Wacom DTU1631", 34623, 19553, 511, 0,
DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xFB =
- { "Wacom DTU1031", 22096, 13960, 511, 0,
+ { "Wacom DTU1031", 21896, 13760, 511, 0,
DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
static const struct wacom_features wacom_features_0x32F =
@@ -2742,15 +2742,15 @@ static const struct wacom_features wacom_features_0x5D = /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0xCC =
- { "Wacom Cintiq 21UX2", 87000, 65400, 2047, 63,
+ { "Wacom Cintiq 21UX2", 86800, 65200, 2047, 63,
WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0xFA =
- { "Wacom Cintiq 22HD", 95640, 54060, 2047, 63,
+ { "Wacom Cintiq 22HD", 95440, 53860, 2047, 63,
WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
static const struct wacom_features wacom_features_0x5B =
- { "Wacom Cintiq 22HDT", 95640, 54060, 2047, 63,
+ { "Wacom Cintiq 22HDT", 95440, 53860, 2047, 63,
WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e };
@@ -2897,7 +2897,7 @@ static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", 12800, 8000, 255, 0,
TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x307 =
- { "Wacom ISDv5 307", 59352, 33648, 2047, 63,
+ { "Wacom ISDv5 307", 59152, 33448, 2047, 63,
CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 };
@@ -2906,7 +2906,7 @@ static const struct wacom_features wacom_features_0x309 =
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x0307, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
static const struct wacom_features wacom_features_0x30A =
- { "Wacom ISDv5 30A", 59352, 33648, 2047, 63,
+ { "Wacom ISDv5 30A", 59152, 33448, 2047, 63,
CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C };
--
1.9.1
^ permalink raw reply related
* [PATCH] driver: input :touchscreen : add Raydium I2C touch driver
From: jeffrey.lin @ 2014-12-05 8:15 UTC (permalink / raw)
To: dmitry.torokhov, shc_work, bleung, lee.jones, charliemooney
Cc: KP.li, linux-kernel, linux-input, jeffrey.lin
From: "jeffrey.lin" <jeffrey.lin@rad-ic.com>
This patch is porting Raydium I2C touch driver. Developer can enable raydium touch driver by modifying define
"CONFIG_TOUCHSCREEN_RM_TS".
Signed-off-by: jeffrey.lin@rad-ic.com
---
drivers/input/touchscreen/Kconfig | 12 ++++++++++++
drivers/input/touchscreen/Makefile | 1 +
2 files changed, 13 insertions(+)
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3ce9181..d0324d2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -955,4 +955,16 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_RM_TS
+ tristate "Raydium I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have Raydium series I2C touchscreen,
+ such as RM31100 , connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rm31100_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 687d5a7..3220f66 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_RM_TS) += rm31100_ts.o
--
2.1.2
^ permalink raw reply related
* [PATCH v4] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Yoichi Yuasa @ 2014-12-05 9:17 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: yuasa, linux-input
v4 Changes:
- remove inline
- master_xfer checks in probe()
- rewrite rohm_i2c_burst_read()
- rohm_i2c_burst_read() transfer error returns -EIO
- remove unused module parameters
- fix prev_touch_report update
- pass NULL to hard_irq
- per-device parameters use sysfs
- fix errno
- header file is taken in .c
v3 Changes:
- fix multi touch slots initialization
- fix set_bit BTN_TOUCH
- remove input_unregister_device()
- switch to __set_bit()
v2 Changes:
- remove polling mode
- switch to threaded interrupt
- switch to managed resources
- use MT-B protocol with input_mt_assign_slots
- provide ST emulation
- firmware load and device initialization are shifted at opening the
device
- add error handling for IO operations
Signed-off-by: Yoichi Yuasa <yuasa@linux-mips.org>
---
drivers/input/touchscreen/Kconfig | 11 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/rohm_bu21023.c | 1257 ++++++++++++++++++++++++++++++
3 files changed, 1269 insertions(+)
create mode 100644 drivers/input/touchscreen/rohm_bu21023.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 568a020..80811a7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -975,4 +975,15 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_ROHM_BU21023
+ tristate "ROHM BU21023/24 Dual touch support resistive touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a touchscreen using ROHM BU21023/24.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bu21023_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index dab4a56..5c2917b 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
+obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
new file mode 100644
index 0000000..4c460c6
--- /dev/null
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -0,0 +1,1257 @@
+/*
+ * ROHM BU21023/24 Dual touch support resistive touch screen driver
+ * Copyright (C) 2012 ROHM CO.,LTD.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#define BU21023_NAME "bu21023_ts"
+#define BU21023_FIRMWARE_NAME "bu21023.bin"
+
+#define BU21023_MAX_SLOTS 2
+
+#define AXIS_ADJUST 4
+#define AXIS_OFFSET 8
+
+#define FIRMWARE_BLOCK_SIZE 32
+#define FIRMWARE_RETRY_MAX 4
+
+#define SAMPLING_DELAY 12 /* msec */
+
+#define CALIBRATION_RETRY_MAX 6
+
+#define ROHM_TS_ABS_X_MIN 40
+#define ROHM_TS_ABS_X_MAX 990
+#define ROHM_TS_ABS_Y_MIN 160
+#define ROHM_TS_ABS_Y_MAX 920
+
+/*
+ * BU21023GUL/BU21023MUV/BU21024FV-M registers map
+ */
+#define VADOUT_YP_H 0x00
+#define VADOUT_YP_L 0x01
+#define VADOUT_XP_H 0x02
+#define VADOUT_XP_L 0x03
+#define VADOUT_YN_H 0x04
+#define VADOUT_YN_L 0x05
+#define VADOUT_XN_H 0x06
+#define VADOUT_XN_L 0x07
+
+#define PRM1_X_H 0x08
+#define PRM1_X_L 0x09
+#define PRM1_Y_H 0x0a
+#define PRM1_Y_L 0x0b
+#define PRM2_X_H 0x0c
+#define PRM2_X_L 0x0d
+#define PRM2_Y_H 0x0e
+#define PRM2_Y_L 0x0f
+
+#define MLT_PRM_MONI_X 0x10
+#define MLT_PRM_MONI_Y 0x11
+
+#define DEBUG_MONI_1 0x12
+#define DEBUG_MONI_2 0x13
+
+#define VADOUT_ZX_H 0x14
+#define VADOUT_ZX_L 0x15
+#define VADOUT_ZY_H 0x16
+#define VADOUT_ZY_L 0x17
+
+#define Z_PARAM_H 0x18
+#define Z_PARAM_L 0x19
+
+/*
+ * Value for VADOUT_*_L
+ */
+#define VADOUT_L_MASK 0x01
+
+/*
+ * Value for PRM*_*_L
+ */
+#define PRM_L_MASK 0x01
+
+#define POS_X1_H 0x20
+#define POS_X1_L 0x21
+#define POS_Y1_H 0x22
+#define POS_Y1_L 0x23
+#define POS_X2_H 0x24
+#define POS_X2_L 0x25
+#define POS_Y2_H 0x26
+#define POS_Y2_L 0x27
+
+/*
+ * Value for POS_*_L
+ */
+#define POS_L_MASK 0x01
+
+#define TOUCH 0x28
+#define TOUCH_DETECT 0x01
+
+#define TOUCH_GESTURE 0x29
+#define SINGLE_TOUCH 0x01
+#define DUAL_TOUCH 0x03
+#define TOUCH_MASK 0x03
+#define CALIBRATION_REQUEST 0x04
+#define CALIBRATION_STATUS 0x08
+#define CALIBRATION_MASK 0x0c
+#define GESTURE_SPREAD 0x10
+#define GESTURE_PINCH 0x20
+#define GESTURE_ROTATE_R 0x40
+#define GESTURE_ROTATE_L 0x80
+
+#define INT_STATUS 0x2a
+#define INT_MASK 0x3d
+#define INT_CLEAR 0x3e
+
+/*
+ * Values for INT_*
+ */
+#define COORD_UPDATE 0x01
+#define CALIBRATION_DONE 0x02
+#define SLEEP_IN 0x04
+#define SLEEP_OUT 0x08
+#define PROGRAM_LOAD_DONE 0x10
+#define ERROR 0x80
+#define INT_ALL 0x9f
+
+#define ERR_STATUS 0x2b
+#define ERR_MASK 0x3f
+
+/*
+ * Values for ERR_*
+ */
+#define ADC_TIMEOUT 0x01
+#define CPU_TIMEOUT 0x02
+#define CALIBRATION_ERR 0x04
+#define PROGRAM_LOAD_ERR 0x10
+
+#define COMMON_SETUP1 0x30
+#define PROGRAM_LOAD_HOST 0x02
+#define PROGRAM_LOAD_EEPROM 0x03
+#define CENSOR_4PORT 0x04
+#define CENSOR_8PORT 0x00 /* Not supported by BU21023 */
+#define CALIBRATION_TYPE_DEFAULT 0x08
+#define CALIBRATION_TYPE_SPECIAL 0x00
+#define INT_ACTIVE_HIGH 0x10
+#define INT_ACTIVE_LOW 0x00
+#define AUTO_CALIBRATION 0x40
+#define MANUAL_CALIBRATION 0x00
+#define COMMON_SETUP1_DEFAULT 0x4e
+
+#define COMMON_SETUP2 0x31
+#define MAF_NONE 0x00
+#define MAF_1SAMPLE 0x01
+#define MAF_3SAMPLES 0x02
+#define MAF_5SAMPLES 0x03
+#define INV_Y 0x04
+#define INV_X 0x08
+#define SWAP_XY 0x10
+
+#define COMMON_SETUP3 0x32
+#define EN_SLEEP 0x01
+#define EN_MULTI 0x02
+#define EN_GESTURE 0x04
+#define EN_INTVL 0x08
+#define SEL_STEP 0x10
+#define SEL_MULTI 0x20
+#define SEL_TBL_DEFAULT 0x40
+
+#define INTERVAL_TIME 0x33
+#define INTERVAL_TIME_DEFAULT 0x10
+
+#define STEP_X 0x34
+#define STEP_X_DEFAULT 0x41
+
+#define STEP_Y 0x35
+#define STEP_Y_DEFAULT 0x8d
+
+#define OFFSET_X 0x38
+#define OFFSET_X_DEFAULT 0x0c
+
+#define OFFSET_Y 0x39
+#define OFFSET_Y_DEFAULT 0x0c
+
+#define THRESHOLD_TOUCH 0x3a
+#define THRESHOLD_TOUCH_DEFAULT 0xa0
+
+#define THRESHOLD_GESTURE 0x3b
+#define THRESHOLD_GESTURE_DEFAULT 0x17
+
+#define SYSTEM 0x40
+#define ANALOG_POWER_ON 0x01
+#define ANALOG_POWER_OFF 0x00
+#define CPU_POWER_ON 0x02
+#define CPU_POWER_OFF 0x00
+
+#define FORCE_CALIBRATION 0x42
+#define FORCE_CALIBRATION_ON 0x01
+#define FORCE_CALIBRATION_OFF 0x00
+
+#define CPU_FREQ 0x50 /* 10 / (reg + 1) MHz */
+#define CPU_FREQ_10MHZ 0x00
+#define CPU_FREQ_5MHZ 0x01
+#define CPU_FREQ_1MHZ 0x09
+
+#define EEPROM_ADDR 0x51
+
+#define CALIBRATION_ADJUST 0x52
+#define CALIBRATION_ADJUST_DEFAULT 0x00
+
+#define THRESHOLD_SLEEP_IN 0x53
+
+#define EVR_XY 0x56
+#define EVR_XY_DEFAULT 0x10
+
+#define PRM_SWOFF_TIME 0x57
+#define PRM_SWOFF_TIME_DEFAULT 0x04
+
+#define PROGRAM_VERSION 0x5f
+
+#define ADC_CTRL 0x60
+#define ADC_DIV_MASK 0x1f /* The minimum value is 4 */
+#define ADC_DIV_DEFAULT 0x08
+
+#define ADC_WAIT 0x61
+#define ADC_WAIT_DEFAULT 0x0a
+
+#define SWCONT 0x62
+#define SWCONT_DEFAULT 0x0f
+
+#define EVR_X 0x63
+#define EVR_X_DEFAULT 0x86
+
+#define EVR_Y 0x64
+#define EVR_Y_DEFAULT 0x64
+
+#define TEST1 0x65
+#define DUALTOUCH_STABILIZE_ON 0x01
+#define DUALTOUCH_STABILIZE_OFF 0x00
+#define DUALTOUCH_REG_ON 0x20
+#define DUALTOUCH_REG_OFF 0x00
+
+#define CALIBRATION_REG1 0x68
+#define CALIBRATION_REG1_DEFAULT 0xd9
+
+#define CALIBRATION_REG2 0x69
+#define CALIBRATION_REG2_DEFAULT 0x36
+
+#define CALIBRATION_REG3 0x6a
+#define CALIBRATION_REG3_DEFAULT 0x32
+
+#define EX_ADDR_H 0x70
+#define EX_ADDR_L 0x71
+#define EX_WDAT 0x72
+#define EX_RDAT 0x73
+#define EX_CHK_SUM1 0x74
+#define EX_CHK_SUM2 0x75
+#define EX_CHK_SUM3 0x76
+
+struct rohm_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+
+ bool initialized;
+
+ unsigned int untouch_count;
+ unsigned int single_touch_count;
+ unsigned int dual_touch_count;
+ unsigned int prev_touch_report;
+
+ u8 setup2;
+};
+
+/*
+ * rohm_i2c_burst_read - execute combined I2C message for ROHM BU21023/24
+ * @client: Handle to ROHM BU21023/24
+ * @start: Where to start read address from ROHM BU21023/24
+ * @buf: Where to store read data from ROHM BU21023/24
+ * @len: How many bytes to read
+ *
+ * Returns negative errno, else zero on success.
+ *
+ * Note
+ * In BU21023/24 burst read, stop condition is needed after "address write".
+ * Therefore, transmission is performed in 2 steps.
+ */
+static int rohm_i2c_burst_read(struct i2c_client *client, u8 start, void *buf,
+ size_t len)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg[2];
+ int i, ret = 0;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &start;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = buf;
+
+ i2c_lock_adapter(adap);
+
+ for (i = 0; i < 2; i++) {
+ if (__i2c_transfer(adap, &msg[i], 1) < 0) {
+ ret = -EIO;
+ break;
+ }
+ }
+
+ i2c_unlock_adapter(adap);
+
+ return ret;
+}
+
+static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
+{
+ struct i2c_client *client = ts->client;
+ struct device *dev = &client->dev;
+ u8 buf[33];
+
+ int retry;
+ bool success = false;
+ bool first_time = true;
+ bool calibration_done;
+
+ u8 reg1, reg2, reg3;
+ s32 reg1_orig, reg2_orig, reg3_orig;
+ s32 val;
+
+ int calib_x = 0, calib_y = 0;
+ int reg_x, reg_y;
+ int err_x, err_y;
+
+ int err = 0, ret;
+ int i;
+
+ reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1);
+ if (reg1_orig < 0)
+ return reg1_orig;
+
+ reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2);
+ if (reg2_orig < 0)
+ return reg2_orig;
+
+ reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3);
+ if (reg3_orig < 0)
+ return reg3_orig;
+
+ ret = i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | SLEEP_IN | SLEEP_OUT |
+ PROGRAM_LOAD_DONE);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, TEST1, DUALTOUCH_STABILIZE_ON);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) {
+ /* wait 2 sampling for update */
+ mdelay(2 * SAMPLING_DELAY);
+
+#define READ_CALIB_BUF(reg) ((u16)buf[((reg) - PRM1_X_H)])
+
+ ret = rohm_i2c_burst_read(client, PRM1_X_H, buf, sizeof(buf));
+ if (ret < 0) {
+ err = ret;
+ goto err_exit;
+ }
+
+ if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT)
+ continue;
+
+ if (first_time) {
+ /* generate calibration parameter */
+ calib_x =
+ (READ_CALIB_BUF(PRM1_X_H) << 2 |
+ READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET;
+ calib_y =
+ (READ_CALIB_BUF(PRM1_Y_H) << 2 |
+ READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET;
+
+ ret = i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON |
+ DUALTOUCH_REG_ON);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ first_time = false;
+ } else {
+ /* generate adjustment parameter */
+ err_x = READ_CALIB_BUF(PRM1_X_H) << 2 |
+ READ_CALIB_BUF(PRM1_X_L);
+ err_y = READ_CALIB_BUF(PRM1_Y_H) << 2 |
+ READ_CALIB_BUF(PRM1_Y_L);
+
+ /* X axis ajust */
+ if (err_x <= 4)
+ calib_x -= AXIS_ADJUST;
+ else if (err_x >= 60)
+ calib_x += AXIS_ADJUST;
+
+ /* Y axis ajust */
+ if (err_y <= 4)
+ calib_y -= AXIS_ADJUST;
+ else if (err_y >= 60)
+ calib_y += AXIS_ADJUST;
+ }
+
+ /* generate calibration setting value */
+ reg_x = calib_x + ((calib_x & 0x200) << 1);
+ reg_y = calib_y + ((calib_y & 0x200) << 1);
+
+ /* convert for register format */
+ reg1 = reg_x >> 3;
+ reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7);
+ reg3 = reg_y >> 3;
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG1, reg1);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG2, reg2);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG3, reg3);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ /*
+ * force calibration sequcence
+ */
+ ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_OFF);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_ON);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ /* clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ /*
+ * Wait for the status change of calibration, max 10 sampling
+ */
+ calibration_done = false;
+
+ for (i = 0; i < 10; i++) {
+ mdelay(SAMPLING_DELAY);
+
+ val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE);
+ if (!(val & CALIBRATION_MASK)) {
+ calibration_done = true;
+ break;
+ } else if (val < 0) {
+ err = val;
+ goto err_exit;
+ }
+ }
+
+ if (calibration_done) {
+ val = i2c_smbus_read_byte_data(client, INT_STATUS);
+ if (val == CALIBRATION_DONE) {
+ success = true;
+ break;
+ } else if (val < 0) {
+ err = val;
+ goto err_exit;
+ }
+ } else {
+ dev_warn(dev, "Calibration timeout\n");
+ }
+ }
+
+ if (!success) {
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
+ reg1_orig);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
+ reg2_orig);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
+ reg3_orig);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ /* calibration data enable */
+ ret = i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON |
+ DUALTOUCH_REG_ON);
+ if (ret) {
+ err = ret;
+ goto err_exit;
+ }
+
+ /* wait 10 sampling */
+ mdelay(10 * SAMPLING_DELAY);
+
+ err = -EBUSY;
+ }
+
+err_exit:
+ ret = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+ if (!ret)
+ /* Clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+
+ if (!err && ret)
+ err = ret;
+
+ return err;
+}
+
+static unsigned int untouch_threshold[3] = { 0, 1, 5 };
+static unsigned int single_touch_threshold[3] = { 0, 0, 4 };
+static unsigned int dual_touch_threshold[3] = { 10, 8, 0 };
+
+module_param_array(untouch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(single_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(dual_touch_threshold, uint, NULL, S_IRUGO | S_IWUSR);
+
+MODULE_PARM_DESC(untouch_threshold, "Thresholds for un-touch detection");
+MODULE_PARM_DESC(single_touch_threshold,
+ "Thresholds for single touch detection");
+MODULE_PARM_DESC(dual_touch_threshold, "Thresholds for dual touch detection");
+
+static irqreturn_t rohm_ts_soft_irq(int irq, void *dev_id)
+{
+ struct rohm_ts_data *ts = dev_id;
+ struct i2c_client *client = ts->client;
+ struct input_dev *input_dev = ts->input_dev;
+ struct device *dev = &client->dev;
+
+ u8 buf[10]; /* for 0x20-0x29 */
+
+ struct input_mt_pos pos[BU21023_MAX_SLOTS];
+ int slots[BU21023_MAX_SLOTS];
+ u8 touch_flags;
+ unsigned int threshold;
+ int touch_report = -1;
+ unsigned int prev_touch_report = ts->prev_touch_report;
+
+ s32 status;
+ int i, ret;
+
+ status = i2c_smbus_read_byte_data(client, INT_STATUS);
+ if (!status)
+ return IRQ_NONE;
+
+ if (status < 0)
+ return IRQ_HANDLED;
+
+ ret = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+ if (ret)
+ return IRQ_HANDLED;
+
+ /* Clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+ if (ret)
+ return IRQ_HANDLED;
+
+#define READ_POS_BUF(reg) ((u16)buf[((reg) - POS_X1_H)])
+
+ ret = rohm_i2c_burst_read(client, POS_X1_H, buf, sizeof(buf));
+ if (ret < 0)
+ return IRQ_HANDLED;
+
+ touch_flags = READ_POS_BUF(TOUCH_GESTURE) & TOUCH_MASK;
+ if (touch_flags) {
+ /* generate coordinates */
+ pos[0].x = (READ_POS_BUF(POS_X1_H) << 2) |
+ READ_POS_BUF(POS_X1_L);
+ pos[0].y = (READ_POS_BUF(POS_Y1_H) << 2) |
+ READ_POS_BUF(POS_Y1_L);
+ pos[1].x = (READ_POS_BUF(POS_X2_H) << 2) |
+ READ_POS_BUF(POS_X2_L);
+ pos[1].y = (READ_POS_BUF(POS_Y2_H) << 2) |
+ READ_POS_BUF(POS_Y2_L);
+
+ switch (touch_flags) {
+ case SINGLE_TOUCH:
+ ts->untouch_count = 0;
+ ts->single_touch_count++;
+ ts->dual_touch_count = 0;
+
+ threshold = single_touch_threshold[prev_touch_report];
+ if (ts->single_touch_count > threshold)
+ touch_report = 1;
+
+ if (touch_report == 1) {
+ if (pos[1].x != 0 && pos[1].y != 0) {
+ pos[0].x = pos[1].x;
+ pos[0].y = pos[1].y;
+ pos[1].x = 0;
+ pos[1].y = 0;
+ }
+ }
+ break;
+ case DUAL_TOUCH:
+ ts->untouch_count = 0;
+ ts->single_touch_count = 0;
+ ts->dual_touch_count++;
+
+ threshold = dual_touch_threshold[prev_touch_report];
+ if (ts->dual_touch_count > threshold)
+ touch_report = 2;
+ break;
+ default:
+ dev_dbg(dev,
+ "Three or more touches are not supported\n");
+ return IRQ_HANDLED;
+ }
+ } else {
+ ts->untouch_count++;
+
+ threshold = untouch_threshold[prev_touch_report];
+ if (ts->untouch_count > threshold) {
+ ts->untouch_count = 0;
+ ts->single_touch_count = 0;
+ ts->dual_touch_count = 0;
+
+ touch_report = 0;
+ }
+ }
+
+ if (touch_report >= 0) {
+ input_mt_assign_slots(input_dev, slots, pos, touch_report);
+
+ for (i = 0; i < touch_report; i++) {
+ input_mt_slot(input_dev, slots[i]);
+ input_mt_report_slot_state(input_dev,
+ MT_TOOL_FINGER, true);
+ input_report_abs(input_dev,
+ ABS_MT_POSITION_X, pos[i].x);
+ input_report_abs(input_dev,
+ ABS_MT_POSITION_Y, pos[i].y);
+ }
+
+ input_mt_sync_frame(input_dev);
+ input_mt_report_pointer_emulation(input_dev, true);
+ input_sync(input_dev);
+
+ ts->prev_touch_report = touch_report;
+ }
+
+ if (READ_POS_BUF(TOUCH_GESTURE) & CALIBRATION_REQUEST) {
+ if (rohm_ts_manual_calibration(ts) < 0)
+ dev_warn(dev, "Failed to manual calibration\n");
+ }
+
+ i2c_smbus_write_byte_data(client, INT_MASK,
+ CALIBRATION_DONE | SLEEP_OUT | SLEEP_IN |
+ PROGRAM_LOAD_DONE);
+
+ return IRQ_HANDLED;
+}
+
+static int rohm_ts_load_firmware(struct i2c_client *client,
+ const char *firmware_name)
+{
+ struct device *dev = &client->dev;
+ const struct firmware *firmware = NULL;
+ s32 status;
+ int blocks, remainder, retry = 0, offset;
+ int err = 0, ret;
+ int i;
+
+ ret = request_firmware(&firmware, firmware_name, dev);
+ if (ret) {
+ dev_err(dev, "Unable to open firmware %s\n", firmware_name);
+ return ret;
+ }
+
+ blocks = firmware->size / FIRMWARE_BLOCK_SIZE;
+ remainder = firmware->size % FIRMWARE_BLOCK_SIZE;
+
+ ret = i2c_smbus_write_byte_data(client, INT_MASK,
+ COORD_UPDATE | CALIBRATION_DONE |
+ SLEEP_IN | SLEEP_OUT);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ while (retry < FIRMWARE_RETRY_MAX) {
+ ret = i2c_smbus_write_byte_data(client, COMMON_SETUP1,
+ COMMON_SETUP1_DEFAULT);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, EX_ADDR_H, 0);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, EX_ADDR_L, 0);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ offset = 0;
+
+ /* firmware load to the device */
+ for (i = 0; i < blocks; i++) {
+ ret = i2c_smbus_write_i2c_block_data(client, EX_WDAT,
+ FIRMWARE_BLOCK_SIZE, &firmware->data[offset]);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ offset += FIRMWARE_BLOCK_SIZE;
+ }
+
+ if (remainder) {
+ ret = i2c_smbus_write_i2c_block_data(client, EX_WDAT,
+ remainder, &firmware->data[offset]);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+ }
+
+ /* check formware load result */
+ status = i2c_smbus_read_byte_data(client, INT_STATUS);
+ if (status < 0) {
+ err = status;
+ goto err_int_mask_exit;
+ }
+
+ /* clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ if (status == PROGRAM_LOAD_DONE)
+ break;
+
+ /* settings for retry */
+ ret = i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+ if (ret) {
+ err = ret;
+ goto err_int_mask_exit;
+ }
+
+ retry++;
+ dev_warn(dev, "Retry firmware load\n");
+ }
+
+err_int_mask_exit:
+ ret = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
+ if (ret)
+ err = ret;
+
+ release_firmware(firmware);
+
+ if (retry >= FIRMWARE_RETRY_MAX)
+ return -EBUSY;
+
+ return err;
+}
+
+static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+
+ ts = input_get_drvdata(input_dev);
+
+ return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
+}
+
+static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+ unsigned int val;
+ int err = 0;
+
+ ts = input_get_drvdata(input_dev);
+
+ err = kstrtouint(buf, 0, &val);
+ if (err)
+ return err;
+
+ if (val)
+ ts->setup2 |= SWAP_XY;
+ else
+ ts->setup2 &= ~SWAP_XY;
+
+ if (ts->initialized)
+ err = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
+ ts->setup2);
+
+ return err;
+}
+
+static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+
+ ts = input_get_drvdata(input_dev);
+
+ return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X));
+}
+
+static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+ unsigned int val;
+ int err = 0;
+
+ ts = input_get_drvdata(input_dev);
+
+ err = kstrtouint(buf, 0, &val);
+ if (err)
+ return err;
+
+ if (val)
+ ts->setup2 |= INV_X;
+ else
+ ts->setup2 &= ~INV_X;
+
+ if (ts->initialized)
+ err = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
+ ts->setup2);
+
+ return err;
+}
+
+static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+
+ ts = input_get_drvdata(input_dev);
+
+ return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y));
+}
+
+static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct input_dev *input_dev = to_input_dev(dev);
+ struct rohm_ts_data *ts;
+ unsigned int val;
+ int err = 0;
+
+ ts = input_get_drvdata(input_dev);
+
+ err = kstrtouint(buf, 0, &val);
+ if (err)
+ return err;
+
+ if (val)
+ ts->setup2 |= INV_X;
+ else
+ ts->setup2 &= ~INV_X;
+
+ if (ts->initialized)
+ err = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
+ ts->setup2);
+
+ return err;
+}
+
+static DEVICE_ATTR_RW(swap_xy);
+static DEVICE_ATTR_RW(inv_x);
+static DEVICE_ATTR_RW(inv_y);
+
+static struct attribute *rohm_ts_attrs[] = {
+ &dev_attr_swap_xy.attr,
+ &dev_attr_inv_x.attr,
+ &dev_attr_inv_y.attr,
+ NULL,
+};
+
+static const struct attribute_group rohm_ts_attr_group = {
+ .attrs = rohm_ts_attrs,
+};
+
+static int rohm_ts_device_init(struct rohm_ts_data *ts)
+{
+ struct i2c_client *client = ts->client;
+ struct device *dev = &client->dev;
+ int ret;
+
+ /*
+ * Wait 200usec for reset
+ */
+ udelay(200);
+
+ /* Release analog reset */
+ ret = i2c_smbus_write_byte_data(client, SYSTEM, ANALOG_POWER_ON);
+ if (ret)
+ return ret;
+
+ /* Waiting for the analog warm-up, max. 200usec */
+ udelay(200);
+
+ /* clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, EX_WDAT, 0);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, COMMON_SETUP1, 0);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, COMMON_SETUP2, ts->setup2);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, COMMON_SETUP3,
+ SEL_TBL_DEFAULT | EN_MULTI);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, THRESHOLD_GESTURE,
+ THRESHOLD_GESTURE_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, INTERVAL_TIME,
+ INTERVAL_TIME_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, CPU_FREQ, CPU_FREQ_10MHZ);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, PRM_SWOFF_TIME,
+ PRM_SWOFF_TIME_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADC_CTRL, ADC_DIV_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADC_WAIT, ADC_WAIT_DEFAULT);
+ if (ret)
+ return ret;
+
+ /*
+ * Panel setup, these values change with the panel.
+ */
+ ret = i2c_smbus_write_byte_data(client, STEP_X, STEP_X_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, STEP_Y, STEP_Y_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, OFFSET_X, OFFSET_X_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, OFFSET_Y, OFFSET_Y_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, THRESHOLD_TOUCH,
+ THRESHOLD_TOUCH_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, EVR_XY, EVR_XY_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, EVR_X, EVR_X_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, EVR_Y, EVR_Y_DEFAULT);
+ if (ret)
+ return ret;
+
+ /* Fixed value settings */
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_ADJUST,
+ CALIBRATION_ADJUST_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, SWCONT, SWCONT_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, TEST1,
+ DUALTOUCH_STABILIZE_ON |
+ DUALTOUCH_REG_ON);
+ if (ret)
+ return ret;
+
+ ret = rohm_ts_load_firmware(client, BU21023_FIRMWARE_NAME);
+ if (ret) {
+ dev_err(dev, "Failed to firmware load\n");
+ return ret;
+ }
+
+ /*
+ * Manual calibration results are not changed in same environment.
+ * If the force calibration is performed,
+ * the controller will not require calibration request interrupt
+ * when the typical values are set to the calibration registers.
+ */
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
+ CALIBRATION_REG1_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
+ CALIBRATION_REG2_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
+ CALIBRATION_REG3_DEFAULT);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_OFF);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
+ FORCE_CALIBRATION_ON);
+ if (ret)
+ return ret;
+
+ /* Clear all interrupts */
+ ret = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
+ if (ret)
+ return ret;
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ rohm_ts_soft_irq, IRQF_TRIGGER_FALLING,
+ client->name, ts);
+ if (ret) {
+ dev_err(dev, "Unable to request IRQ\n");
+ return ret;
+ }
+
+ /* Enable coordinates update interrupt */
+ ret = i2c_smbus_write_byte_data(client, INT_MASK,
+ CALIBRATION_DONE |
+ SLEEP_OUT | SLEEP_IN |
+ PROGRAM_LOAD_DONE);
+ if (ret)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ERR_MASK,
+ PROGRAM_LOAD_ERR | CPU_TIMEOUT |
+ ADC_TIMEOUT);
+ if (ret)
+ return ret;
+
+ /* controller CPU power on */
+ ret = i2c_smbus_write_byte_data(client, SYSTEM,
+ CPU_POWER_ON | ANALOG_POWER_ON);
+
+ return ret;
+}
+
+static int rohm_ts_open(struct input_dev *input_dev)
+{
+ struct rohm_ts_data *ts = input_get_drvdata(input_dev);
+ struct i2c_client *client = ts->client;
+ int ret;
+
+ if (!ts->initialized) {
+ ret = rohm_ts_device_init(ts);
+ if (ret) {
+ dev_err(&client->dev,
+ "Failed to device initialization\n");
+ return ret;
+ }
+
+ ts->initialized = true;
+ }
+
+ return 0;
+}
+
+static int rohm_bu21023_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rohm_ts_data *ts;
+ struct i2c_adapter *adap = client->adapter;
+ struct device *dev = &client->dev;
+ struct input_dev *input_dev;
+ int ret;
+
+ if (!client->irq) {
+ dev_err(dev, "IRQ is not assigned\n");
+ return -EINVAL;
+ }
+
+ if (!adap->algo->master_xfer) {
+ dev_err(&adap->dev, "I2C level transfers not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ts = devm_kzalloc(dev, sizeof(struct rohm_ts_data), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ ts->client = client;
+ ts->setup2 = MAF_1SAMPLE;
+ i2c_set_clientdata(client, ts);
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->name = BU21023_NAME;
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->open = rohm_ts_open;
+
+ ts->input_dev = input_dev;
+ input_set_drvdata(input_dev, ts);
+
+ __set_bit(EV_SYN, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_X,
+ ROHM_TS_ABS_X_MIN, ROHM_TS_ABS_X_MAX, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ ROHM_TS_ABS_Y_MIN, ROHM_TS_ABS_Y_MAX, 0, 0);
+
+ ret = input_mt_init_slots(input_dev, BU21023_MAX_SLOTS,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (ret) {
+ dev_err(dev, "Failed to multi touch slots initialization\n");
+ return ret;
+ }
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ dev_err(dev, "Unable to register input device\n");
+ return ret;
+ }
+
+ ret = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group);
+ if (ret)
+ dev_err(dev, "Failed to create sysfs group\n");
+
+ return ret;
+}
+
+static int rohm_bu21023_i2c_remove(struct i2c_client *client)
+{
+ int ret;
+
+ sysfs_remove_group(&client->dev.kobj, &rohm_ts_attr_group);
+
+ ret = i2c_smbus_write_byte_data(client, SYSTEM,
+ ANALOG_POWER_ON | CPU_POWER_OFF);
+ if (ret)
+ return ret;
+
+ return i2c_smbus_write_byte_data(client, SYSTEM,
+ ANALOG_POWER_OFF | CPU_POWER_OFF);
+}
+
+static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
+ {BU21023_NAME, 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
+
+static struct i2c_driver rohm_bu21023_i2c_driver = {
+ .driver = {
+ .name = BU21023_NAME,
+ },
+ .probe = rohm_bu21023_i2c_probe,
+ .remove = rohm_bu21023_i2c_remove,
+ .id_table = rohm_bu21023_i2c_id,
+};
+
+module_i2c_driver(rohm_bu21023_i2c_driver);
+
+MODULE_DESCRIPTION("ROHM BU21023/24 Touchscreen driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ROHM Co., Ltd.");
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Maxime Ripard @ 2014-12-05 10:01 UTC (permalink / raw)
To: vishnupatekar
Cc: linux-sunxi, robh+dt, benh, msalter, ralf, jdelvare, linux-kernel,
linux-input, linux-arm-kernel, devicetree, dmitry.torokhov
In-Reply-To: <1417647224-27950-1-git-send-email-VishnuPatekar0510@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 13381 bytes --]
Hi,
Thanks for working on this.
First, make sure to read Documentation/SubmittingPatches. The
guidelines in there might seem tedious, but it's there to enforce that
we keep the kernel homogenous.
Most notably, you should make sure that:
- you run scripts/checkpatch.pl on your patches
- you have a commit log
- your commit title stays below 80 chars
- you have a Signed-off-by in your commit log
On Thu, Dec 04, 2014 at 04:23:44AM +0530, vishnupatekar wrote:
> ---
> drivers/input/serio/Kconfig | 9 ++
> drivers/input/serio/Makefile | 1 +
> drivers/input/serio/sunxi-ps2.c | 305 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 315 insertions(+)
> create mode 100644 drivers/input/serio/sunxi-ps2.c
>
> diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> index bc2d474..1a86e41 100644
> --- a/drivers/input/serio/Kconfig
> +++ b/drivers/input/serio/Kconfig
> @@ -281,4 +281,13 @@ config HYPERV_KEYBOARD
> To compile this driver as a module, choose M here: the module will
> be called hyperv_keyboard.
>
> +config SERIO_SUNXI_PS2
> + tristate "Allwinner Sun7i-A20 PS/2 controller"
> + default m
> + help
> + Say Y here if you have Sun7i-A20 Allwinner PS/2 ports.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called sunxi-ps2.
> +
> endif
> diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> index 815d874..0fa0f78 100644
> --- a/drivers/input/serio/Makefile
> +++ b/drivers/input/serio/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
> obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
> obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
> +obj-$(CONFIG_SERIO_SUNXI_PS2) += sunxi-ps2.o
> diff --git a/drivers/input/serio/sunxi-ps2.c b/drivers/input/serio/sunxi-ps2.c
> new file mode 100644
> index 0000000..ccd7b29
> --- /dev/null
> +++ b/drivers/input/serio/sunxi-ps2.c
> @@ -0,0 +1,305 @@
> +/*
> + * sunxi-ps2.c Support for Allwinner A20 PS2 host controller
> + *
> + * Author: Aaron.maoye <leafy.myeh@newbietech.com>
> + * Vishnu Patekar <vishnupatekar0510@gmail.com>
> + * Based on sunxi-ps2.c 3.0 kernel
Mentionning that it's Allwinner's 3.0 kernel would be good, it doesn't
make much sense otherwise.
> +#include <linux/module.h>
> +#include <linux/serio.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/list.h>
> +#include <linux/io.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_platform.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +
> +#define DRIVER_NAME "sunxi-ps2"
> +
> +#define RESSIZE(res) (((res)->end - (res)->start)+1)
> +
> +#define SW_PS2_GCTRL (0x00)
> +#define SW_PS2_DATA (0x04)
> +#define SW_PS2_LCTRL (0x08)
> +#define SW_PS2_LSTAT (0x0c)
> +#define SW_PS2_FCTRL (0x10)
> +#define SW_PS2_FSTAT (0x14)
> +#define SW_PS2_CLKDR (0x18)
The SW_ prefix is a left over from Allwinner I suppose?
Using a prefix like sun4i_ps2/sun7i_ps2 depending on the outcome of
the discussion you had with Hans would seem better, across all your
driver.
> +
> +/* SW_PS2_GCTRL */
> +#define SWPS2_BUSEN (1 << 0)
> +#define SWPS2_MASTER (1 << 1)
> +#define SWPS2_RESET (1 << 2)
> +#define SWPS2_INTEN (1 << 3)
We usually have the convention of having the register name mentionned
in the bits offsets, and the bits declared right after their register.
Something like:
#define SUN4I_PS2_GCTRL_REG 0x00
#define SUN4I_PS2_GCTRL_BUS_EN BIT(0)
#define SUN4I_PS2_LCTRL_REG 0x08
#define SUN4I_PS2_LCTRL_PAR_ERR_EN BIT(1)
etc....
> +#define SWPS2_INTFLAG (1 << 3)
This is defined to the same value than _INTEN, is this intentionnal?
> +
> +/* SW_PS2_LCTRL */
> +#define SWPS2_LCTL_NOACK (0x0 << 18)
> +#define SWPS2_LCTL_TXDTOEN (0x1 << 8)
> +#define SWPS2_LCTL_STOPERREN (0x1 << 3)
> +#define SWPS2_LCTL_ACKERREN (0x1 << 2)
> +#define SWPS2_LCTL_PARERREN (0x1 << 1)
> +#define SWPS2_LCTL_RXDTOEN (0x1 << 0)
> +
> +/* SW_PS2_FSTAT */
> +#define SWPS2_FSTA_RXRDY (1 << 0)
> +#define SWPS2_FSTA_RXOF (1 << 1)
> +#define SWPS2_FSTA_RXUF (1 << 2)
> +#define SWPS2_FSTA_TXRDY (1 << 8)
> +#define SWPS2_FSTA_TXOF (1 << 9)
> +#define SWPS2_FSTA_TXUF (1 << 10)
> +
> +#define SW_PS2_SAMPLE_CLK (1000000)
> +#define SW_PS2_SCLK (125000)
> +
> +struct sunxips2data {
> + int irq;
> + spinlock_t ps2_lock;
> + void __iomem *base_address; /* virt address of control registers*/
> + struct serio *serio; /* serio*/
> + struct device *dev;
> + struct clk *pclk;
> +};
> +
> +/*********************/
> +/* Interrupt handler */
> +/*********************/
> +static irqreturn_t sunxips2_interrupt(int irq, void *dev_id)
> +{
> + struct sunxips2data *drvdata = dev_id;
> + u32 intr_status;
> + u32 fifo_status;
> + unsigned char byte;
> + u32 rval;
> + u32 error = 0;
> +
> + spin_lock(&drvdata->ps2_lock);
> +
> + /* Get the PS/2 interrupts and clear them */
> + intr_status = readl(drvdata->base_address + SW_PS2_LSTAT);
> + fifo_status = readl(drvdata->base_address + SW_PS2_FSTAT);
> +
> + /*Check Line Status Register*/
> + if (intr_status & 0x10f) {
> + if (intr_status & 0x08)
> + dev_info(drvdata->dev, "PS/2 Stop Bit Error!");
> + if (intr_status & 0x04)
> + dev_info(drvdata->dev, "PS/2 Acknowledge Error!\n");
> + if (intr_status & 0x02)
> + dev_info(drvdata->dev, "PS/2 Parity Error!\n");
> + if (intr_status & 0x100)
> + dev_info(drvdata->dev, "PS/2 Transmit Data Timeout!\n");
> + if (intr_status & 0x01)
> + dev_info(drvdata->dev, "PS/2 Receive Data Timeout!\n");
> +
> + writel(readl(drvdata->base_address + SW_PS2_GCTRL)|0x4, drvdata->base_address + SW_PS2_GCTRL);/*reset PS/2 controller*/
> + writel(0x10f, drvdata->base_address + SW_PS2_LSTAT);
> +
> + error = 1;
> + }
> +
> + /*Check FIFO Status Register*/
> + if (fifo_status & 0x0606) {
> + if (fifo_status & 0x400)
> + dev_info(drvdata->dev, "PS/2 Tx FIFO Underflow!\n");
> + if (fifo_status & 0x200)
> + dev_info(drvdata->dev, "PS/2 Tx FIFO Overflow!\n");
> + if (fifo_status & 0x04)
> + dev_info(drvdata->dev, "PS/2 Rx FIFO Underflow!\n");
> + if (fifo_status & 0x02)
> + dev_info(drvdata->dev, "PS/2 Rx FIFO Overflow!\n");
> +
> + writel(readl(drvdata->base_address + SW_PS2_GCTRL)|0x4, drvdata->base_address + SW_PS2_GCTRL); /*reset PS/2 controller*/
> + writel(0x707, drvdata->base_address + SW_PS2_FSTAT);
> + error = 1;
> + }
> +
> + rval = (fifo_status >> 16) & 0x3;
> + while (!error && rval--) {
> + byte = readl(drvdata->base_address + SW_PS2_DATA) & 0xff;
> + dev_info(drvdata->dev, "PS/2 Receive %02x\n", byte);
> + serio_interrupt(drvdata->serio, byte, 0);
> + }
> +
> + writel(intr_status, drvdata->base_address + SW_PS2_LSTAT);
> + writel(fifo_status, drvdata->base_address + SW_PS2_FSTAT);
> +
> + spin_unlock(&drvdata->ps2_lock);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int sunxips2_open(struct serio *pserio)
> +{
> + struct sunxips2data *drvdata = pserio->port_data;
> + u32 src_clk = 0;
> + u32 clk_scdf;
> + u32 clk_pcdf;
> + u32 rval;
> +
> + /*Set Line Control And Enable Interrupt*/
> + rval = SWPS2_LCTL_TXDTOEN|SWPS2_LCTL_STOPERREN|SWPS2_LCTL_ACKERREN|SWPS2_LCTL_PARERREN|SWPS2_LCTL_RXDTOEN;
> + writel(rval, drvdata->base_address + SW_PS2_LCTRL);
> +
> + /*Reset FIFO*/
> + writel(0x3<<16 | 0x607, drvdata->base_address + SW_PS2_FCTRL);
> +
> + src_clk = clk_get_rate(drvdata->pclk);
> +
> + if (!src_clk) {
> + dev_info(drvdata->dev, "w_ps2c_set_sclk error, source clock is 0.");
> + return -1;
> + }
> +
> + /*Set Clock Divider Register*/
> + clk_scdf = ((src_clk + (SW_PS2_SAMPLE_CLK>>1)) / SW_PS2_SAMPLE_CLK - 1);
> + clk_pcdf = ((SW_PS2_SAMPLE_CLK + (SW_PS2_SCLK>>1)) / SW_PS2_SCLK - 1);
> + rval = (clk_scdf<<8) | clk_pcdf;/* | (PS2_DEBUG_SEL<<16);*/
What is this supposed to do? Calculating and rounding the dividers?
You should look into DIV_ROUND_* if that's so
> + writel(rval, drvdata->base_address + SW_PS2_CLKDR);
> +
> + /*Set Global Control Register*/
> + rval = SWPS2_RESET|SWPS2_INTEN|SWPS2_MASTER|SWPS2_BUSEN;
> + writel(rval, drvdata->base_address + SW_PS2_GCTRL);
> +
> + udelay(100);
Why is that udelay needed?
> +
> + return 0;
> +}
> +
> +static void sunxips2_close(struct serio *pserio)
> +{
> + struct sunxips2data *drvdata = pserio->port_data;
> +
> + spin_lock(&drvdata->ps2_lock);
spin_lock_irqsave would be better I guess.
> + /* Disable the PS2 interrupts */
> + writel(0, drvdata->base_address + SW_PS2_GCTRL);
> + spin_unlock(&drvdata->ps2_lock);
> +}
> +
> +static int sunxips2_write(struct serio *pserio, unsigned char val)
> +{
> + struct sunxips2data *drvdata = (struct sunxips2data *)pserio->port_data;
> + u32 timeout = 10000;
> +
> + do {
> + if (readl(drvdata->base_address + SW_PS2_FSTAT) & SWPS2_FSTA_TXRDY) {
> + writel(val, drvdata->base_address + SW_PS2_DATA);
> + return 0;
> + }
> + } while (timeout--);
Please use time_before() here
> + return -1;
And return a meaningful error.
> +static int sunxips2_probe(struct platform_device *ofdev)
The ofdev name is measleading. This is a platform_device structure, it
could be probed by other mechanisms than OF, so please use a different
name here. Usually pdev is used.
> +{
> + struct resource *res; /* IO mem resources */
> + struct sunxips2data *drvdata;
> + struct serio *serio;
> + struct device *dev = &ofdev->dev;
> + unsigned int irq;
> + int error;
> +
> + drvdata = devm_kzalloc(dev, sizeof(struct sunxips2data), GFP_KERNEL);
> + serio = devm_kzalloc(dev, sizeof(struct serio), GFP_KERNEL);
> + if (!drvdata || !serio)
> + error = -ENOMEM;
> +
> + /* Request clock */
> + drvdata->pclk = clk_get(dev, NULL);
You can use devm_clk_get.
> + if (IS_ERR(drvdata->pclk))
> + dev_dbg(dev, "couldn't get clock %li\n",
> + PTR_ERR(drvdata->pclk));
This is an error, you should treat it as such.
> + if (!IS_ERR(drvdata->pclk)) {
> + error = clk_prepare_enable(drvdata->pclk);
> + if (error < 0) {
> + dev_err(dev, "failed to enable clock %d\n", error);
> + return error;
> + }
> + }
> +
> + /* IO */
> + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
> + drvdata->base_address = devm_ioremap_resource(dev, res);
> + if (IS_ERR(drvdata->base_address)) {
> + dev_err(dev, "failed to map registers\n");
> + error = PTR_ERR(drvdata->base_address);
> + }
ditto.
> + serio->id.type = SERIO_8042;
> + serio->write = sunxips2_write;
> + serio->open = sunxips2_open;
> + serio->close = sunxips2_close;
> + serio->port_data = drvdata;
> + serio->dev.parent = dev;
> + strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> + strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> +
> + platform_set_drvdata(ofdev, drvdata);
> + serio_register_port(serio);
> +
> + /* Get IRQ for the device */
> + irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
> + if (!irq) {
> + dev_err(dev, "no IRQ found\n");
> + return -ENODEV;
> + }
You can use platform_get_irq, for consistency with how you retrieve
resources.
You're also no unregistering the driver from the serio framework.
> + drvdata->irq = irq;
> + drvdata->serio = serio;
> + drvdata->dev = dev;
> + error = devm_request_any_context_irq(drvdata->dev, drvdata->irq, &sunxips2_interrupt, 0,
> + DRIVER_NAME, drvdata);
request_irq is enough here.
> + if (error) {
> + dev_err(drvdata->dev,
> + "Couldn't allocate interrupt %d : error: %d\n", drvdata->irq, error);
> + return error;
> + }
> + return 0; /* success */
> +}
> +
> +static int sunxips2_remove(struct platform_device *of_dev)
> +{
> + struct sunxips2data *drvdata = platform_get_drvdata(of_dev);
> +
> + if (!IS_ERR(drvdata->pclk)) {
> + clk_disable_unprepare(drvdata->pclk);
> + clk_put(drvdata->pclk);
> + }
> + serio_unregister_port(drvdata->serio);
> + mdelay(2);
Why a mdelay?
> + return 0;
> +}
> +
> +/* Match table for of_platform binding */
> +static const struct of_device_id sunxips2_of_match[] = {
> + { .compatible = "allwinner,sun7i-a20-ps2", },
> + { },
> +};
> +
> +MODULE_DEVICE_TABLE(of, sunxips2_of_match);
> +
> +/*platform driver structure*/
> +static struct platform_driver sunxips2_of_driver = {
> + .probe = sunxips2_probe,
> + .remove = sunxips2_remove,
> + .driver = {
> + .name = DRIVER_NAME,
> + .owner = THIS_MODULE,
You can drop the owner field, it's already set by
module_platform_driver.
> + .of_match_table = sunxips2_of_match,
> + },
> +};
> +module_platform_driver(sunxips2_of_driver);
> +
> +MODULE_AUTHOR("Aaron.maoye<leafy.myeh@newbietech.com, "
> + "Vishnu Patekar <vishnupatekar0510@gmail.com>");
Usually, you define two MODULE_AUTHOR.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Arnd Bergmann @ 2014-12-05 10:33 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: vishnupatekar, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ralf-6z/3iImG2C8G8FEW9MqTrA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, msalter-H+wXaHxf7aLQT0dZR+AlfA,
vishnupatekar, jdelvare-l3A5Bk7waGM
In-Reply-To: <1417647224-27950-1-git-send-email-VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thursday 04 December 2014 04:23:44 vishnupatekar wrote:
> +
> +#define DRIVER_NAME "sunxi-ps2"
> +
> +#define RESSIZE(res) (((res)->end - (res)->start)+1)
Remove this and use the existing resource_size() function
> +
> +struct sunxips2data {
> + int irq;
> + spinlock_t ps2_lock;
> + void __iomem *base_address; /* virt address of control registers*/
> + struct serio *serio; /* serio*/
> + struct device *dev;
> + struct clk *pclk;
> +};
As this is dynamically allocated, better embed the serio member
directly to avoid allocating both separately.
> +static int sunxips2_open(struct serio *pserio)
> +{
> + struct sunxips2data *drvdata = pserio->port_data;
> + u32 src_clk = 0;
> + u32 clk_scdf;
> + u32 clk_pcdf;
> + u32 rval;
> +
> + /*Set Line Control And Enable Interrupt*/
> + rval = SWPS2_LCTL_TXDTOEN|SWPS2_LCTL_STOPERREN|SWPS2_LCTL_ACKERREN|SWPS2_LCTL_PARERREN|SWPS2_LCTL_RXDTOEN;
> + writel(rval, drvdata->base_address + SW_PS2_LCTRL);
> +
> + /*Reset FIFO*/
> + writel(0x3<<16 | 0x607, drvdata->base_address + SW_PS2_FCTRL);
> +
> + src_clk = clk_get_rate(drvdata->pclk);
> +
> + if (!src_clk) {
> + dev_info(drvdata->dev, "w_ps2c_set_sclk error, source clock is 0.");
> + return -1;
> + }
> +
> + /*Set Clock Divider Register*/
> + clk_scdf = ((src_clk + (SW_PS2_SAMPLE_CLK>>1)) / SW_PS2_SAMPLE_CLK - 1);
> + clk_pcdf = ((SW_PS2_SAMPLE_CLK + (SW_PS2_SCLK>>1)) / SW_PS2_SCLK - 1);
> + rval = (clk_scdf<<8) | clk_pcdf;/* | (PS2_DEBUG_SEL<<16);*/
> + writel(rval, drvdata->base_address + SW_PS2_CLKDR);
> +
> + /*Set Global Control Register*/
> + rval = SWPS2_RESET|SWPS2_INTEN|SWPS2_MASTER|SWPS2_BUSEN;
> + writel(rval, drvdata->base_address + SW_PS2_GCTRL);
> +
> + udelay(100);
100 microseconds is a rather long time to block the CPU for, so this
needs a comment explaining why the particular delay is needed and why
you can't use usleep_range() instead.
> +static void sunxips2_close(struct serio *pserio)
> +{
> + struct sunxips2data *drvdata = pserio->port_data;
> +
> + spin_lock(&drvdata->ps2_lock);
> + /* Disable the PS2 interrupts */
> + writel(0, drvdata->base_address + SW_PS2_GCTRL);
> + spin_unlock(&drvdata->ps2_lock);
> +}
The locking is wrong here: you take the lock without disabling the
interrupts first, so if the interrupt happens between the spin_lock()
call and the writel(), the kernel will deadlock.
You will either have to use spin_lock_irq() here, or find a justification
for dropping the lock entirely.
> +static int sunxips2_write(struct serio *pserio, unsigned char val)
> +{
> + struct sunxips2data *drvdata = (struct sunxips2data *)pserio->port_data;
> + u32 timeout = 10000;
> +
> + do {
> + if (readl(drvdata->base_address + SW_PS2_FSTAT) & SWPS2_FSTA_TXRDY) {
> + writel(val, drvdata->base_address + SW_PS2_DATA);
> + return 0;
> + }
> + } while (timeout--);
> +
> + return -1;
> +}
We never return '-1' from in-kernel functions. Either make this a bool
argument, or return a proper errno.h value. This should probably return
-EIO.
> + drvdata->irq = irq;
> + drvdata->serio = serio;
> + drvdata->dev = dev;
> + error = devm_request_any_context_irq(drvdata->dev, drvdata->irq, &sunxips2_interrupt, 0,
> + DRIVER_NAME, drvdata);
> + if (error) {
> + dev_err(drvdata->dev,
> + "Couldn't allocate interrupt %d : error: %d\n", drvdata->irq, error);
> + return error;
> + }
> + return 0; /* success */
> +}
Why any_context?
Arnd
^ permalink raw reply
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Dmitry Torokhov @ 2014-12-05 15:01 UTC (permalink / raw)
To: Arnd Bergmann, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: vishnupatekar, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ralf-6z/3iImG2C8G8FEW9MqTrA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, msalter-H+wXaHxf7aLQT0dZR+AlfA,
vishnupatekar, jdelvare-l3A5Bk7waGM
In-Reply-To: <12237550.afophX20rO@wuerfel>
Hi Arnd,
On December 5, 2014 2:33:11 AM PST, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
>On Thursday 04 December 2014 04:23:44 vishnupatekar wrote:
>> +
>> +struct sunxips2data {
>> + int irq;
>> + spinlock_t ps2_lock;
>> + void __iomem *base_address; /* virt address of control registers*/
>> + struct serio *serio; /* serio*/
>> + struct device *dev;
>> + struct clk *pclk;
>> +};
>
>As this is dynamically allocated, better embed the serio member
>directly to avoid allocating both separately.
That would be wrong - serio is refcounted and it may outlive instance of sunxips2data you embedded it into.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH] driver: input :touchscreen : add Raydium I2C touch driver
From: Dmitry Torokhov @ 2014-12-05 15:04 UTC (permalink / raw)
To: jeffrey.lin, shc_work, bleung, lee.jones, charliemooney
Cc: KP.li, linux-kernel, linux-input, jeffrey.lin
In-Reply-To: <1417767301-20141-1-git-send-email-jeffrey.lin@rad-ic.com>
Hi Jeffrey,
On December 5, 2014 12:15:01 AM PST, "jeffrey.lin" <yajohn@gmail.com> wrote:
>From: "jeffrey.lin" <jeffrey.lin@rad-ic.com>
>
>This patch is porting Raydium I2C touch driver. Developer can enable
>raydium touch driver by modifying define
>"CONFIG_TOUCHSCREEN_RM_TS".
>
>Signed-off-by: jeffrey.lin@rad-ic.com
>---
> drivers/input/touchscreen/Kconfig | 12 ++++++++++++
> drivers/input/touchscreen/Makefile | 1 +
> 2 files changed, 13 insertions(+)
>
>diff --git a/drivers/input/touchscreen/Kconfig
>b/drivers/input/touchscreen/Kconfig
>index 3ce9181..d0324d2 100644
>--- a/drivers/input/touchscreen/Kconfig
>+++ b/drivers/input/touchscreen/Kconfig
>@@ -955,4 +955,16 @@ config TOUCHSCREEN_ZFORCE
> To compile this driver as a module, choose M here: the
> module will be called zforce_ts.
>
>+config TOUCHSCREEN_RM_TS
>+ tristate "Raydium I2C Touchscreen"
>+ depends on I2C
>+ help
>+ Say Y here if you have Raydium series I2C touchscreen,
>+ such as RM31100 , connected to your system.
>+
>+ If unsure, say N.
>+
>+ To compile this driver as a module, choose M here: the
>+ module will be called rm31100_ts.
>+
> endif
>diff --git a/drivers/input/touchscreen/Makefile
>b/drivers/input/touchscreen/Makefile
>index 687d5a7..3220f66 100644
>--- a/drivers/input/touchscreen/Makefile
>+++ b/drivers/input/touchscreen/Makefile
>@@ -78,3 +78,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) +=
>zylonite-wm97xx.o
> obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
> obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
> obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
>+obj-$(CONFIG_TOUCHSCREEN_RM_TS) += rm31100_ts.o
The source to the driver itself is missing, you only sent make file and kconfig changes.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Arnd Bergmann @ 2014-12-05 15:50 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, vishnupatekar,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ralf-6z/3iImG2C8G8FEW9MqTrA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, msalter-H+wXaHxf7aLQT0dZR+AlfA,
vishnupatekar, jdelvare-l3A5Bk7waGM
In-Reply-To: <63D786FF-B293-4FC1-AD71-D99515DE8E3D-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Friday 05 December 2014 07:01:17 Dmitry Torokhov wrote:
>
> On December 5, 2014 2:33:11 AM PST, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
> >On Thursday 04 December 2014 04:23:44 vishnupatekar wrote:
> >> +
> >> +struct sunxips2data {
> >> + int irq;
> >> + spinlock_t ps2_lock;
> >> + void __iomem *base_address; /* virt address of control registers*/
> >> + struct serio *serio; /* serio*/
> >> + struct device *dev;
> >> + struct clk *pclk;
> >> +};
> >
> >As this is dynamically allocated, better embed the serio member
> >directly to avoid allocating both separately.
>
> That would be wrong - serio is refcounted and it may outlive instance of sunxips2data you embedded it into.
Ok, I see. I guess in this case the use of devm_kzalloc for serio is a bug,
because that would lead to a double free upon module unload, right?
Arnd
^ permalink raw reply
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Dmitry Torokhov @ 2014-12-05 15:53 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, vishnupatekar,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ralf-6z/3iImG2C8G8FEW9MqTrA,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, msalter-H+wXaHxf7aLQT0dZR+AlfA,
vishnupatekar, jdelvare-l3A5Bk7waGM
In-Reply-To: <2906898.Fr1ixVkiAI@wuerfel>
On December 5, 2014 7:50:18 AM PST, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org> wrote:
>On Friday 05 December 2014 07:01:17 Dmitry Torokhov wrote:
>>
>> On December 5, 2014 2:33:11 AM PST, Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
>wrote:
>> >On Thursday 04 December 2014 04:23:44 vishnupatekar wrote:
>> >> +
>> >> +struct sunxips2data {
>> >> + int irq;
>> >> + spinlock_t ps2_lock;
>> >> + void __iomem *base_address; /* virt address of control
>registers*/
>> >> + struct serio *serio; /* serio*/
>> >> + struct device *dev;
>> >> + struct clk *pclk;
>> >> +};
>> >
>> >As this is dynamically allocated, better embed the serio member
>> >directly to avoid allocating both separately.
>>
>> That would be wrong - serio is refcounted and it may outlive instance
>of sunxips2data you embedded it into.
>
>Ok, I see. I guess in this case the use of devm_kzalloc for serio is a
>bug,
>because that would lead to a double free upon module unload, right?
>
Exactly. I already mentioned that in my review.
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH v2 2/3] HID: wacom: Initialize MT slots for generic devices at post_parse_hid
From: Jason Gerecke @ 2014-12-05 21:37 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, benjamin.tissoires, pinglinux, Jason Gerecke
If a HID descriptor places HID_DG_CONTACTID before HID_DG_X and HID_DG_Y then
the ABS_X and ABS_Y will not be automatically initialized by the call to
input_mt_init_slots. To ensure that this is not a problem, we relocate that
call to occur after HID parsing has been completed and we've initalized all
the multitouch axes.
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
---
Changes from v1:
* Patch renamed from "HID: wacom: Manually declare ABS_{X,Y} for pointer emulation"
* Patch moves call to input_mt_init_slots rather than manually declare ABS_{X,Y}
drivers/hid/wacom_sys.c | 18 ++++++++++++++++++
drivers/hid/wacom_wac.c | 3 ---
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index eb55316..872aa0b 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -13,6 +13,7 @@
#include "wacom_wac.h"
#include "wacom.h"
+#include <linux/input/mt.h>
#define WAC_MSG_RETRIES 5
@@ -236,6 +237,21 @@ static void wacom_usage_mapping(struct hid_device *hdev,
wacom_wac_usage_mapping(hdev, field, usage);
}
+static void wacom_post_parse_hid(struct hid_device *hdev,
+ struct wacom_features *features)
+{
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+
+ if (features->type == HID_GENERIC) {
+ /* Any last-minute generic device setup */
+ if (features->touch_max > 1) {
+ input_mt_init_slots(wacom_wac->input, wacom_wac->features.touch_max,
+ INPUT_MT_DIRECT);
+ }
+ }
+}
+
static void wacom_parse_hid(struct hid_device *hdev,
struct wacom_features *features)
{
@@ -270,6 +286,8 @@ static void wacom_parse_hid(struct hid_device *hdev,
wacom_usage_mapping(hdev, hreport->field[i],
hreport->field[i]->usage + j);
}
+
+ wacom_post_parse_hid(hdev, features);
}
static int wacom_hid_set_device_mode(struct hid_device *hdev)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index a8a19a5..c33f889 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1381,7 +1381,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
- struct input_dev *input = wacom_wac->input;
unsigned touch_max = wacom_wac->features.touch_max;
switch (usage->hid) {
@@ -1400,8 +1399,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
ABS_MT_POSITION_Y, 4);
break;
case HID_DG_CONTACTID:
- input_mt_init_slots(input, wacom_wac->features.touch_max,
- INPUT_MT_DIRECT);
break;
case HID_DG_INRANGE:
break;
--
2.1.3
^ permalink raw reply related
* [PATCH v2 3/3] HID: wacom: Report input events for each finger on generic devices
From: Jason Gerecke @ 2014-12-05 21:37 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, benjamin.tissoires, pinglinux, Jason Gerecke
In-Reply-To: <1417815453-10618-1-git-send-email-killertofu@gmail.com>
The existing generic touch code only reports events after reading an
entire HID report, which practically means that only data about the last
contact in a report will ever be provided to userspace. This patch uses
a trick from hid-multitouch.c to discover what type of field is at the
end of each contact; when such a field is encountered all the stored
contact data will be reported.
Signed-off-by: Jason Gerecke <killertofu@gmail.com>
---
Changes from v1:
* Patch renamed from "HID: wacom: Report input events immediately upon receipt"
* Instead of reporting on-reciept, events are bundled and sent at the end of each contact
* Adds code to discover 'last_slot_field' based on hid-multitouch.c implementation
drivers/hid/wacom_wac.c | 94 ++++++++++++++++++++++++++++++++-----------------
drivers/hid/wacom_wac.h | 1 +
2 files changed, 63 insertions(+), 32 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index c33f889..75fc16e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1381,35 +1381,68 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
- unsigned touch_max = wacom_wac->features.touch_max;
+ struct wacom_features *features = &wacom_wac->features;
switch (usage->hid) {
case HID_GD_X:
- if (touch_max == 1)
+ features->last_slot_field = usage->hid;
+ if (features->touch_max == 1)
wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4);
else
wacom_map_usage(wacom, usage, field, EV_ABS,
ABS_MT_POSITION_X, 4);
break;
case HID_GD_Y:
- if (touch_max == 1)
+ features->last_slot_field = usage->hid;
+ if (features->touch_max == 1)
wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4);
else
wacom_map_usage(wacom, usage, field, EV_ABS,
ABS_MT_POSITION_Y, 4);
break;
case HID_DG_CONTACTID:
+ features->last_slot_field = usage->hid;
break;
case HID_DG_INRANGE:
+ features->last_slot_field = usage->hid;
break;
case HID_DG_INVERT:
+ features->last_slot_field = usage->hid;
break;
case HID_DG_TIPSWITCH:
+ features->last_slot_field = usage->hid;
wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0);
break;
}
}
+static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac,
+ struct input_dev *input)
+{
+ struct hid_data *hid_data = &wacom_wac->hid_data;
+ bool mt = wacom_wac->features.touch_max > 1;
+ bool prox = hid_data->tipswitch &&
+ !wacom_wac->shared->stylus_in_proximity;
+
+ if (mt) {
+ int slot;
+
+ slot = input_mt_get_slot_by_key(input, hid_data->id);
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, prox);
+ }
+ else {
+ input_report_key(input, BTN_TOUCH, prox);
+ }
+
+ if (prox) {
+ input_report_abs(input, mt ? ABS_MT_POSITION_X : ABS_X,
+ hid_data->x);
+ input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y,
+ hid_data->y);
+ }
+}
+
static int wacom_wac_finger_event(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage, __s32 value)
{
@@ -1432,36 +1465,35 @@ static int wacom_wac_finger_event(struct hid_device *hdev,
}
+ if (usage->usage_index + 1 == field->report_count) {
+ if (usage->hid == wacom_wac->features.last_slot_field)
+ wacom_wac_finger_slot(wacom_wac, wacom_wac->input);
+ }
+
return 0;
}
-static void wacom_wac_finger_mt_report(struct wacom_wac *wacom_wac,
- struct input_dev *input, bool touch)
+static int wacom_wac_finger_touches(struct hid_device *hdev)
{
- int slot;
- struct hid_data *hid_data = &wacom_wac->hid_data;
+ struct wacom *wacom = hid_get_drvdata(hdev);
+ struct wacom_wac *wacom_wac = &wacom->wacom_wac;
+ struct input_dev *input = wacom_wac->input;
+ unsigned touch_max = wacom_wac->features.touch_max;
+ int count = 0;
+ int i;
- slot = input_mt_get_slot_by_key(input, hid_data->id);
+ if (touch_max == 1)
+ return wacom_wac->hid_data.tipswitch &&
+ !wacom_wac->shared->stylus_in_proximity;
- input_mt_slot(input, slot);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
- if (touch) {
- input_report_abs(input, ABS_MT_POSITION_X, hid_data->x);
- input_report_abs(input, ABS_MT_POSITION_Y, hid_data->y);
+ for (i = 0; i < input->mt->num_slots; i++) {
+ struct input_mt_slot *ps = &input->mt->slots[i];
+ int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+ if (id >= 0)
+ count++;
}
- input_mt_sync_frame(input);
-}
-
-static void wacom_wac_finger_single_touch_report(struct wacom_wac *wacom_wac,
- struct input_dev *input, bool touch)
-{
- struct hid_data *hid_data = &wacom_wac->hid_data;
- if (touch) {
- input_report_abs(input, ABS_X, hid_data->x);
- input_report_abs(input, ABS_Y, hid_data->y);
- }
- input_report_key(input, BTN_TOUCH, touch);
+ return count;
}
static void wacom_wac_finger_report(struct hid_device *hdev,
@@ -1470,18 +1502,16 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct input_dev *input = wacom_wac->input;
- bool touch = wacom_wac->hid_data.tipswitch &&
- !wacom_wac->shared->stylus_in_proximity;
- unsigned touch_max = wacom_wac->features.touch_max;
- if (touch_max > 1)
- wacom_wac_finger_mt_report(wacom_wac, input, touch);
+ if (wacom_wac->features.touch_max > 1)
+ input_mt_sync_frame(input);
else
- wacom_wac_finger_single_touch_report(wacom_wac, input, touch);
+ wacom_wac_finger_slot(wacom_wac, input);
+
input_sync(input);
/* keep touch state for pen event */
- wacom_wac->shared->touch_down = touch;
+ wacom_wac->shared->touch_down = wacom_wac_finger_touches(hdev);
}
#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index 128cbb3..6e256206 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -144,6 +144,7 @@ struct wacom_features {
int pktlen;
bool check_for_hid_type;
int hid_type;
+ int last_slot_field;
};
struct wacom_shared {
--
2.1.3
^ permalink raw reply related
* Re: [PATCH 1/4] alps: v7: Document the v7 touchpad packet protocol
From: Benjamin Tissoires @ 2014-12-05 21:58 UTC (permalink / raw)
To: Hans de Goede; +Cc: Dmitry Torokhov, linux-input, Benjamin Tissoires
In-Reply-To: <1417613268-13674-1-git-send-email-hdegoede@redhat.com>
On Wed, Dec 3, 2014 at 8:27 AM, Hans de Goede <hdegoede@redhat.com> wrote:
> Add a table documenting where all the bits are in the v7 touchpad packets.
>
> Cc: stable@vger.kernel.org # 3.17
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
Hi Hans,
I tested yesterday the series on a Toshiba W50-A and a Z30-A if my
memory is accurate. Internal QA tested these on a Dell M4700 (don't
know if it has a v7 touchpad though).
Both tests were conclusive, i.e. they fixes the spurious release when
right-clicking.
Tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
I am not confident enough with the code to review 3/4 and 4/4, but
they look sane to me.
Cheers,
Benjamin
> drivers/input/mouse/alps.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index d125a01..aceaade 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -881,6 +881,34 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
> unsigned char *pkt,
> unsigned char pkt_id)
> {
> + /*
> + * packet-fmt b7 b6 b5 b4 b3 b2 b1 b0
> + * Byte0 TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0
> + * Byte0 NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0
> + * Byte1 Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
> + * Byte2 X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
> + * Byte3 X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0
> + * Byte4 TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
> + * Byte4 MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1
> + * Byte4 NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0
> + * Byte5 TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
> + * Byte5 MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0
> + * L: Left button
> + * R / M: Non-clickpads: Right / Middle button
> + * Clickpads: When > 2 fingers are down, and some fingers
> + * are in the button area, then the 2 coordinates reported
> + * are for fingers outside the button area and these report
> + * extra fingers being present in the right / left button
> + * area. Note these fingers are not added to the F field!
> + * so if a TWO packet is received and R = 1 then there are
> + * 3 fingers down, etc.
> + * TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt
> + * 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
> + * otherwise byte 0 bit 4 must be set and byte 0/4/5 are
> + * in NEW fmt
> + * F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
> + */
> +
> mt[0].x = ((pkt[2] & 0x80) << 4);
> mt[0].x |= ((pkt[2] & 0x3F) << 5);
> mt[0].x |= ((pkt[3] & 0x30) >> 1);
> --
> 2.1.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v2 2/3] HID: wacom: Initialize MT slots for generic devices at post_parse_hid
From: Benjamin Tissoires @ 2014-12-05 22:00 UTC (permalink / raw)
To: Jason Gerecke; +Cc: Jiri Kosina, linux-input, Ping Cheng
In-Reply-To: <1417815453-10618-1-git-send-email-killertofu@gmail.com>
On Fri, Dec 5, 2014 at 4:37 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> If a HID descriptor places HID_DG_CONTACTID before HID_DG_X and HID_DG_Y then
> the ABS_X and ABS_Y will not be automatically initialized by the call to
> input_mt_init_slots. To ensure that this is not a problem, we relocate that
> call to occur after HID parsing has been completed and we've initalized all
> the multitouch axes.
>
> Signed-off-by: Jason Gerecke <killertofu@gmail.com>
> ---
This one is
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Thanks for the v2 Jason!
Cheers,
Benjamin
> Changes from v1:
> * Patch renamed from "HID: wacom: Manually declare ABS_{X,Y} for pointer emulation"
> * Patch moves call to input_mt_init_slots rather than manually declare ABS_{X,Y}
>
> drivers/hid/wacom_sys.c | 18 ++++++++++++++++++
> drivers/hid/wacom_wac.c | 3 ---
> 2 files changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
> index eb55316..872aa0b 100644
> --- a/drivers/hid/wacom_sys.c
> +++ b/drivers/hid/wacom_sys.c
> @@ -13,6 +13,7 @@
>
> #include "wacom_wac.h"
> #include "wacom.h"
> +#include <linux/input/mt.h>
>
> #define WAC_MSG_RETRIES 5
>
> @@ -236,6 +237,21 @@ static void wacom_usage_mapping(struct hid_device *hdev,
> wacom_wac_usage_mapping(hdev, field, usage);
> }
>
> +static void wacom_post_parse_hid(struct hid_device *hdev,
> + struct wacom_features *features)
> +{
> + struct wacom *wacom = hid_get_drvdata(hdev);
> + struct wacom_wac *wacom_wac = &wacom->wacom_wac;
> +
> + if (features->type == HID_GENERIC) {
> + /* Any last-minute generic device setup */
> + if (features->touch_max > 1) {
> + input_mt_init_slots(wacom_wac->input, wacom_wac->features.touch_max,
> + INPUT_MT_DIRECT);
> + }
> + }
> +}
> +
> static void wacom_parse_hid(struct hid_device *hdev,
> struct wacom_features *features)
> {
> @@ -270,6 +286,8 @@ static void wacom_parse_hid(struct hid_device *hdev,
> wacom_usage_mapping(hdev, hreport->field[i],
> hreport->field[i]->usage + j);
> }
> +
> + wacom_post_parse_hid(hdev, features);
> }
>
> static int wacom_hid_set_device_mode(struct hid_device *hdev)
> diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
> index a8a19a5..c33f889 100644
> --- a/drivers/hid/wacom_wac.c
> +++ b/drivers/hid/wacom_wac.c
> @@ -1381,7 +1381,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
> {
> struct wacom *wacom = hid_get_drvdata(hdev);
> struct wacom_wac *wacom_wac = &wacom->wacom_wac;
> - struct input_dev *input = wacom_wac->input;
> unsigned touch_max = wacom_wac->features.touch_max;
>
> switch (usage->hid) {
> @@ -1400,8 +1399,6 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev,
> ABS_MT_POSITION_Y, 4);
> break;
> case HID_DG_CONTACTID:
> - input_mt_init_slots(input, wacom_wac->features.touch_max,
> - INPUT_MT_DIRECT);
> break;
> case HID_DG_INRANGE:
> break;
> --
> 2.1.3
>
^ permalink raw reply
* Re: [PATCH 1/2] HID: wacom - Add support for DTU-1031X
From: Jiri Kosina @ 2014-12-05 22:24 UTC (permalink / raw)
To: Ping Cheng; +Cc: linux-input, Ping Cheng
In-Reply-To: <1417746184-12192-1-git-send-email-pingc@wacom.com>
Both applied, thanks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH 1/1] x86: Surface Pro 3 Type Cover 3
From: Jarrad Whitaker @ 2014-12-06 10:57 UTC (permalink / raw)
To: Jiri Kosina; +Cc: Alan Wu, linux-input, linux-kernel, linux-usb
In-Reply-To: <alpine.LNX.2.00.1411052137430.29198@pobox.suse.cz>
[-- Attachment #1: Type: text/plain, Size: 4893 bytes --]
Hey guys,
Sorry for the very slow reply, I broke my build dir and was in the
middle of exams. Tested successfully (keyboard works after a hotplug)
with 3.18-rc7.
Jarrad
On 6 November 2014 at 07:39, Jiri Kosina <jkosina@suse.cz> wrote:
> On Mon, 3 Nov 2014, Alan Wu wrote:
>
>> Surface Pro 3 Type Cover that works with Ubuntu (and possibly Arch) from this thread. Both trackpad and keyboard work after compiling my own kernel.
>> http://ubuntuforums.org/showthread.php?t=2231207&page=2&s=44910e0c56047e4f93dfd9fea58121ef
>>
>> Also includes Jarrad Whitaker's message which sources
>> http://winaero.com/blog/how-to-install-linux-on-surface-pro-3/
>> which he says is sourced from a Russian site
>>
>> Signed-off-by: Alan Wu <alan.c.wu@gmail.com>
>
> Adding Jarrad to CC so that he can test your patch as well.
>
> Jarrad, if you could provide your Tested-by: to Alan's patch, I'd
> appreciate it (that would mean that we've reached the right super-position
> of both the patches you guys submitted).
>
> I don't own the device, so I fully depend on what you guys submit and
> test.
>
> Thanks.
>
>> ---
>> drivers/hid/hid-core.c | 6 ++++++
>> drivers/hid/hid-ids.h | 1 +
>> drivers/hid/hid-microsoft.c | 2 ++
>> drivers/hid/usbhid/hid-quirks.c | 1 +
>> 4 files changed, 10 insertions(+)
>>
>> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
>> index 73bd9e2..e94afcc 100644
>> --- a/drivers/hid/hid-core.c
>> +++ b/drivers/hid/hid-core.c
>> @@ -702,6 +702,11 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
>> if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
>> type == HID_COLLECTION_PHYSICAL)
>> hid->group = HID_GROUP_SENSOR_HUB;
>> +
>> + if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
>> + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 &&
>> + hid->group == HID_GROUP_MULTITOUCH)
>> + hid->group = HID_GROUP_GENERIC;
>> }
>>
>> static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
>> @@ -1861,6 +1866,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
>> { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
>> { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
>> { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
>> + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
>> { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
>> { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
>> { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
>> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
>> index e23ab8b..15f32c2 100644
>> --- a/drivers/hid/hid-ids.h
>> +++ b/drivers/hid/hid-ids.h
>> @@ -648,6 +648,7 @@
>> #define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
>> #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
>> #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
>> +#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc
>>
>> #define USB_VENDOR_ID_MOJO 0x8282
>> #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
>> diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
>> index 8ba17a9..cacda43 100644
>> --- a/drivers/hid/hid-microsoft.c
>> +++ b/drivers/hid/hid-microsoft.c
>> @@ -274,6 +274,8 @@ static const struct hid_device_id ms_devices[] = {
>> .driver_data = MS_NOGET },
>> { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
>> .driver_data = MS_DUPLICATE_USAGES },
>> + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
>> + .driver_data = MS_HIDINPUT },
>>
>> { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
>> .driver_data = MS_PRESENTER },
>> diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
>> index 5014bb5..cebfaf2 100644
>> --- a/drivers/hid/usbhid/hid-quirks.c
>> +++ b/drivers/hid/usbhid/hid-quirks.c
>> @@ -77,6 +77,7 @@ static const struct hid_blacklist {
>> { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
>> { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
>> { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
>> + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
>> { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
>> { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
>> { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
>> --
>> 2.1.0
>>
>
> --
> Jiri Kosina
> SUSE Labs
[-- Attachment #2: s3.patch --]
[-- Type: text/x-patch, Size: 3484 bytes --]
Signed-off-by: Alan Wu <alan.c.wu@xxxxxxxxx>
Tested-by: Jarrad Whitaker <jarrad.whitaker@gmail.com>
---
drivers/hid/hid-core.c | 6 ++++++
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-microsoft.c | 2 ++
drivers/hid/usbhid/hid-quirks.c | 1 +
4 files changed, 10 insertions(+)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 73bd9e2..e94afcc 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -702,6 +702,11 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
+
+ if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
+ hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 &&
+ hid->group == HID_GROUP_MULTITOUCH)
+ hid->group = HID_GROUP_GENERIC;
}
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
@@ -1861,6 +1866,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e23ab8b..15f32c2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -648,6 +648,7 @@
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
+#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 8ba17a9..cacda43 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -274,6 +274,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
.driver_data = MS_DUPLICATE_USAGES },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
+ .driver_data = MS_HIDINPUT },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 5014bb5..cebfaf2 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -77,6 +77,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
^ permalink raw reply related
* Re: Disable input device
From: Pavel Machek @ 2014-12-06 12:47 UTC (permalink / raw)
To: Pali Rohár
Cc: Dmitry Torokhov, Sebastian Reichel, kernel list, linux-input,
Henrik Rydberg
In-Reply-To: <201411291824.03996@pali>
On Sat 2014-11-29 18:24:03, Pali Rohár wrote:
> Hello,
>
> there is request to introduce some option (via sysfs) to disable
> one input device. Originally it was for tsc2005 touchscreen found
> on Nokia N900 cellphone. Use case is to completely disable
> touchscreen when phone is in pocket or when screen is locked via
> slide switch (to prevent random clicks).
>
> But it would be better to have disable option for all input
> devices. Sometimes input device is not use and only consume
> power. Another case is when input device (e.g. keyboard or
> touchpad) is integrated into machine (e.g. on laptops) and user
> does not want to use it (so make sure that kernel does not send
> events to userspace).
>
> I would like to ask, how to solve it?
>
> What do you think about adding new sysfs file "disable" (accept
> values 1 or 0) for every input device? With "1" it cause that
> kernel will drop all events from specific input device and if
> driver provide some function is can be called (e.g. for power
> management or disabling device at hardware level).
That makes sense to me. Dmitry, would such interface be acceptable?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/3] drivers:input:ps2 Added sunxi A20 ps2 driver, changed makefile and Kconfig
From: Vishnu Patekar @ 2014-12-06 13:31 UTC (permalink / raw)
To: Maxime Ripard
Cc: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org,
msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org,
jdelvare-l3A5Bk7waGM@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Dmitry Torokhov
In-Reply-To: <20141205100151.GT30256@lukather>
[-- Attachment #1: Type: text/plain, Size: 16674 bytes --]
Hello Maxime,
Sorry for inconvenience. I'll follow the guidelines, will implement the
review comment and resubmit the patch for review.
On Fri, Dec 5, 2014 at 3:31 PM, Maxime Ripard <
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> Hi,
>
> Thanks for working on this.
>
> First, make sure to read Documentation/SubmittingPatches. The
> guidelines in there might seem tedious, but it's there to enforce that
> we keep the kernel homogenous.
>
> Most notably, you should make sure that:
> - you run scripts/checkpatch.pl on your patches
> - you have a commit log
> - your commit title stays below 80 chars
> - you have a Signed-off-by in your commit log
>
> On Thu, Dec 04, 2014 at 04:23:44AM +0530, vishnupatekar wrote:
> > ---
> > drivers/input/serio/Kconfig | 9 ++
> > drivers/input/serio/Makefile | 1 +
> > drivers/input/serio/sunxi-ps2.c | 305
> +++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 315 insertions(+)
> > create mode 100644 drivers/input/serio/sunxi-ps2.c
> >
> > diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
> > index bc2d474..1a86e41 100644
> > --- a/drivers/input/serio/Kconfig
> > +++ b/drivers/input/serio/Kconfig
> > @@ -281,4 +281,13 @@ config HYPERV_KEYBOARD
> > To compile this driver as a module, choose M here: the module
> will
> > be called hyperv_keyboard.
> >
> > +config SERIO_SUNXI_PS2
> > + tristate "Allwinner Sun7i-A20 PS/2 controller"
> > + default m
> > + help
> > + Say Y here if you have Sun7i-A20 Allwinner PS/2 ports.
> > +
> > + To compile this driver as a module, choose M here: the
> > + module will be called sunxi-ps2.
> > +
> > endif
> > diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
> > index 815d874..0fa0f78 100644
> > --- a/drivers/input/serio/Makefile
> > +++ b/drivers/input/serio/Makefile
> > @@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
> > obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
> > obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
> > obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
> > +obj-$(CONFIG_SERIO_SUNXI_PS2) += sunxi-ps2.o
> > diff --git a/drivers/input/serio/sunxi-ps2.c
> b/drivers/input/serio/sunxi-ps2.c
> > new file mode 100644
> > index 0000000..ccd7b29
> > --- /dev/null
> > +++ b/drivers/input/serio/sunxi-ps2.c
> > @@ -0,0 +1,305 @@
> > +/*
> > + * sunxi-ps2.c Support for Allwinner A20 PS2 host controller
> > + *
> > + * Author: Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
> > + * Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> > + * Based on sunxi-ps2.c 3.0 kernel
>
> Mentionning that it's Allwinner's 3.0 kernel would be good, it doesn't
> make much sense otherwise.
>
> Okie
> > +#include <linux/module.h>
> > +#include <linux/serio.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/errno.h>
> > +#include <linux/slab.h>
> > +#include <linux/list.h>
> > +#include <linux/io.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_device.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +
> > +#define DRIVER_NAME "sunxi-ps2"
> > +
> > +#define RESSIZE(res) (((res)->end - (res)->start)+1)
> > +
> > +#define SW_PS2_GCTRL (0x00)
> > +#define SW_PS2_DATA (0x04)
> > +#define SW_PS2_LCTRL (0x08)
> > +#define SW_PS2_LSTAT (0x0c)
> > +#define SW_PS2_FCTRL (0x10)
> > +#define SW_PS2_FSTAT (0x14)
> > +#define SW_PS2_CLKDR (0x18)
>
> The SW_ prefix is a left over from Allwinner I suppose?
>
> Using a prefix like sun4i_ps2/sun7i_ps2 depending on the outcome of
> the discussion you had with Hans would seem better, across all your
> driver.
>
> Agreed, as this PS2 driver can be applicable for A10 and A20, I'll keep it
as PS2_REG_* for registers, e.g. PS2_REG_GCTL and PS2_GCTL_BUSEN for bits.
it is similar to SUNXI MMC driver.
> > +
> > +/* SW_PS2_GCTRL */
> > +#define SWPS2_BUSEN (1 << 0)
> > +#define SWPS2_MASTER (1 << 1)
> > +#define SWPS2_RESET (1 << 2)
> > +#define SWPS2_INTEN (1 << 3)
>
> We usually have the convention of having the register name mentionned
> in the bits offsets, and the bits declared right after their register.
>
> Something like:
>
> #define SUN4I_PS2_GCTRL_REG 0x00
> #define SUN4I_PS2_GCTRL_BUS_EN BIT(0)
>
> #define SUN4I_PS2_LCTRL_REG 0x08
> #define SUN4I_PS2_LCTRL_PAR_ERR_EN BIT(1)
>
> etc....
>
> Agreed, BIT(x) macros will be used.
> > +#define SWPS2_INTFLAG (1 << 3)
>
> This is defined to the same value than _INTEN, is this intentionnal?
>
> This macro is not used, will be removed.
> > +
> > +/* SW_PS2_LCTRL */
> > +#define SWPS2_LCTL_NOACK (0x0 << 18)
> > +#define SWPS2_LCTL_TXDTOEN (0x1 << 8)
> > +#define SWPS2_LCTL_STOPERREN (0x1 << 3)
> > +#define SWPS2_LCTL_ACKERREN (0x1 << 2)
> > +#define SWPS2_LCTL_PARERREN (0x1 << 1)
> > +#define SWPS2_LCTL_RXDTOEN (0x1 << 0)
> > +
> > +/* SW_PS2_FSTAT */
> > +#define SWPS2_FSTA_RXRDY (1 << 0)
> > +#define SWPS2_FSTA_RXOF (1 << 1)
> > +#define SWPS2_FSTA_RXUF (1 << 2)
> > +#define SWPS2_FSTA_TXRDY (1 << 8)
> > +#define SWPS2_FSTA_TXOF (1 << 9)
> > +#define SWPS2_FSTA_TXUF (1 << 10)
> > +
> > +#define SW_PS2_SAMPLE_CLK (1000000)
> > +#define SW_PS2_SCLK (125000)
> > +
> > +struct sunxips2data {
> > + int irq;
> > + spinlock_t ps2_lock;
> > + void __iomem *base_address; /* virt address of control
> registers*/
> > + struct serio *serio; /* serio*/
> > + struct device *dev;
> > + struct clk *pclk;
> > +};
> > +
> > +/*********************/
> > +/* Interrupt handler */
> > +/*********************/
> > +static irqreturn_t sunxips2_interrupt(int irq, void *dev_id)
> > +{
> > + struct sunxips2data *drvdata = dev_id;
> > + u32 intr_status;
> > + u32 fifo_status;
> > + unsigned char byte;
> > + u32 rval;
> > + u32 error = 0;
> > +
> > + spin_lock(&drvdata->ps2_lock);
> > +
> > + /* Get the PS/2 interrupts and clear them */
> > + intr_status = readl(drvdata->base_address + SW_PS2_LSTAT);
> > + fifo_status = readl(drvdata->base_address + SW_PS2_FSTAT);
> > +
> > + /*Check Line Status Register*/
> > + if (intr_status & 0x10f) {
> > + if (intr_status & 0x08)
> > + dev_info(drvdata->dev, "PS/2 Stop Bit Error!");
> > + if (intr_status & 0x04)
> > + dev_info(drvdata->dev, "PS/2 Acknowledge
> Error!\n");
> > + if (intr_status & 0x02)
> > + dev_info(drvdata->dev, "PS/2 Parity Error!\n");
> > + if (intr_status & 0x100)
> > + dev_info(drvdata->dev, "PS/2 Transmit Data
> Timeout!\n");
> > + if (intr_status & 0x01)
> > + dev_info(drvdata->dev, "PS/2 Receive Data
> Timeout!\n");
> > +
> > + writel(readl(drvdata->base_address + SW_PS2_GCTRL)|0x4,
> drvdata->base_address + SW_PS2_GCTRL);/*reset PS/2 controller*/
> > + writel(0x10f, drvdata->base_address + SW_PS2_LSTAT);
> > +
> > + error = 1;
> > + }
> > +
> > + /*Check FIFO Status Register*/
> > + if (fifo_status & 0x0606) {
> > + if (fifo_status & 0x400)
> > + dev_info(drvdata->dev, "PS/2 Tx FIFO
> Underflow!\n");
> > + if (fifo_status & 0x200)
> > + dev_info(drvdata->dev, "PS/2 Tx FIFO Overflow!\n");
> > + if (fifo_status & 0x04)
> > + dev_info(drvdata->dev, "PS/2 Rx FIFO
> Underflow!\n");
> > + if (fifo_status & 0x02)
> > + dev_info(drvdata->dev, "PS/2 Rx FIFO Overflow!\n");
> > +
> > + writel(readl(drvdata->base_address + SW_PS2_GCTRL)|0x4,
> drvdata->base_address + SW_PS2_GCTRL); /*reset PS/2 controller*/
> > + writel(0x707, drvdata->base_address + SW_PS2_FSTAT);
> > + error = 1;
> > + }
> > +
> > + rval = (fifo_status >> 16) & 0x3;
> > + while (!error && rval--) {
> > + byte = readl(drvdata->base_address + SW_PS2_DATA) & 0xff;
> > + dev_info(drvdata->dev, "PS/2 Receive %02x\n", byte);
> > + serio_interrupt(drvdata->serio, byte, 0);
> > + }
> > +
> > + writel(intr_status, drvdata->base_address + SW_PS2_LSTAT);
> > + writel(fifo_status, drvdata->base_address + SW_PS2_FSTAT);
> > +
> > + spin_unlock(&drvdata->ps2_lock);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int sunxips2_open(struct serio *pserio)
> > +{
> > + struct sunxips2data *drvdata = pserio->port_data;
> > + u32 src_clk = 0;
> > + u32 clk_scdf;
> > + u32 clk_pcdf;
> > + u32 rval;
> > +
> > + /*Set Line Control And Enable Interrupt*/
> > + rval =
> SWPS2_LCTL_TXDTOEN|SWPS2_LCTL_STOPERREN|SWPS2_LCTL_ACKERREN|SWPS2_LCTL_PARERREN|SWPS2_LCTL_RXDTOEN;
> > + writel(rval, drvdata->base_address + SW_PS2_LCTRL);
> > +
> > + /*Reset FIFO*/
> > + writel(0x3<<16 | 0x607, drvdata->base_address + SW_PS2_FCTRL);
> > +
> > + src_clk = clk_get_rate(drvdata->pclk);
> > +
> > + if (!src_clk) {
> > + dev_info(drvdata->dev, "w_ps2c_set_sclk error, source
> clock is 0.");
> > + return -1;
> > + }
> > +
> > + /*Set Clock Divider Register*/
> > + clk_scdf = ((src_clk + (SW_PS2_SAMPLE_CLK>>1)) / SW_PS2_SAMPLE_CLK
> - 1);
> > + clk_pcdf = ((SW_PS2_SAMPLE_CLK + (SW_PS2_SCLK>>1)) / SW_PS2_SCLK -
> 1);
> > + rval = (clk_scdf<<8) | clk_pcdf;/* | (PS2_DEBUG_SEL<<16);*/
>
> What is this supposed to do? Calculating and rounding the dividers?
>
> You should look into DIV_ROUND_* if that's so
>
> Yes, Agreed, It'll be used as below, this solves purpose.
clk_scdf = DIV_ROUND_UP(src_clk, PS2_SAMPLE_CLK) -1 ;
clk_pcdf = DIV_ROUND_UP(PS2_SAMPLE_CLK, PS2_SCLK) -1;
rval = (clk_scdf<<8) | clk_pcdf;
writel(rval, drvdata->reg_base + PS2_CLKDR);
> > + writel(rval, drvdata->base_address + SW_PS2_CLKDR);
> > +
> > + /*Set Global Control Register*/
> > + rval = SWPS2_RESET|SWPS2_INTEN|SWPS2_MASTER|SWPS2_BUSEN;
> > + writel(rval, drvdata->base_address + SW_PS2_GCTRL);
> > +
> > + udelay(100);
>
> Why is that udelay needed?
>
> No need, will be removed.
> > +
> > + return 0;
> > +}
> > +
> > +static void sunxips2_close(struct serio *pserio)
> > +{
> > + struct sunxips2data *drvdata = pserio->port_data;
> > +
> > + spin_lock(&drvdata->ps2_lock);
>
> spin_lock_irqsave would be better I guess.
>
> I'll use it.
> > + /* Disable the PS2 interrupts */
> > + writel(0, drvdata->base_address + SW_PS2_GCTRL);
> > + spin_unlock(&drvdata->ps2_lock);
> > +}
> > +
> > +static int sunxips2_write(struct serio *pserio, unsigned char val)
> > +{
> > + struct sunxips2data *drvdata = (struct sunxips2data
> *)pserio->port_data;
> > + u32 timeout = 10000;
> > +
> > + do {
> > + if (readl(drvdata->base_address + SW_PS2_FSTAT) &
> SWPS2_FSTA_TXRDY) {
> > + writel(val, drvdata->base_address + SW_PS2_DATA);
> > + return 0;
> > + }
> > + } while (timeout--);
>
> Please use time_before() here
>
> Agreed, time_before(jiffies, expire) will be used.
> > + return -1;
>
> And return a meaningful error.
>
> Okie
> > +static int sunxips2_probe(struct platform_device *ofdev)
>
> The ofdev name is measleading. This is a platform_device structure, it
> could be probed by other mechanisms than OF, so please use a different
> name here. Usually pdev is used.
>
> > +{
> > + struct resource *res; /* IO mem resources */
> > + struct sunxips2data *drvdata;
> > + struct serio *serio;
> > + struct device *dev = &ofdev->dev;
> > + unsigned int irq;
> > + int error;
> > +
> > + drvdata = devm_kzalloc(dev, sizeof(struct sunxips2data),
> GFP_KERNEL);
> > + serio = devm_kzalloc(dev, sizeof(struct serio), GFP_KERNEL);
> > + if (!drvdata || !serio)
> > + error = -ENOMEM;
> > +
> > + /* Request clock */
> > + drvdata->pclk = clk_get(dev, NULL);
>
> You can use devm_clk_get.
>
> Agreed, devm_clk_get will be used.
> > + if (IS_ERR(drvdata->pclk))
> > + dev_dbg(dev, "couldn't get clock %li\n",
> > + PTR_ERR(drvdata->pclk));
>
> This is an error, you should treat it as such.
>
> > + if (!IS_ERR(drvdata->pclk)) {
> > + error = clk_prepare_enable(drvdata->pclk);
> > + if (error < 0) {
> > + dev_err(dev, "failed to enable clock %d\n", error);
> > + return error;
> > + }
> > + }
> > +
> > + /* IO */
> > + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0);
> > + drvdata->base_address = devm_ioremap_resource(dev, res);
> > + if (IS_ERR(drvdata->base_address)) {
> > + dev_err(dev, "failed to map registers\n");
> > + error = PTR_ERR(drvdata->base_address);
> > + }
>
> ditto.
>
> > + serio->id.type = SERIO_8042;
> > + serio->write = sunxips2_write;
> > + serio->open = sunxips2_open;
> > + serio->close = sunxips2_close;
> > + serio->port_data = drvdata;
> > + serio->dev.parent = dev;
> > + strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
> > + strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
> > +
> > + platform_set_drvdata(ofdev, drvdata);
> > + serio_register_port(serio);
> > +
> > + /* Get IRQ for the device */
> > + irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
> > + if (!irq) {
> > + dev_err(dev, "no IRQ found\n");
> > + return -ENODEV;
> > + }
>
> You can use platform_get_irq, for consistency with how you retrieve
> resources.
>
> You're also no unregistering the driver from the serio framework.
>
> I'll put code for error handling and freeing allocated resources.
> > + drvdata->irq = irq;
> > + drvdata->serio = serio;
> > + drvdata->dev = dev;
> > + error = devm_request_any_context_irq(drvdata->dev, drvdata->irq,
> &sunxips2_interrupt, 0,
> > + DRIVER_NAME, drvdata);
>
> request_irq is enough here.
>
> Okie, I'll use devm_request_threaded_irq as request_irq is just wrapper
arroud it.
> > + if (error) {
> > + dev_err(drvdata->dev,
> > + "Couldn't allocate interrupt %d : error: %d\n",
> drvdata->irq, error);
> > + return error;
> > + }
> > + return 0; /* success */
> > +}
> > +
> > +static int sunxips2_remove(struct platform_device *of_dev)
> > +{
> > + struct sunxips2data *drvdata = platform_get_drvdata(of_dev);
> > +
> > + if (!IS_ERR(drvdata->pclk)) {
> > + clk_disable_unprepare(drvdata->pclk);
> > + clk_put(drvdata->pclk);
> > + }
> > + serio_unregister_port(drvdata->serio);
> > + mdelay(2);
>
> Why a mdelay?
>
No need, will be removed.
>
> > + return 0;
> > +}
> > +
> > +/* Match table for of_platform binding */
> > +static const struct of_device_id sunxips2_of_match[] = {
> > + { .compatible = "allwinner,sun7i-a20-ps2", },
> > + { },
> > +};
> > +
> > +MODULE_DEVICE_TABLE(of, sunxips2_of_match);
> > +
> > +/*platform driver structure*/
> > +static struct platform_driver sunxips2_of_driver = {
> > + .probe = sunxips2_probe,
> > + .remove = sunxips2_remove,
> > + .driver = {
> > + .name = DRIVER_NAME,
> > + .owner = THIS_MODULE,
>
> You can drop the owner field, it's already set by
> module_platform_driver.
>
> Okie
> > + .of_match_table = sunxips2_of_match,
> > + },
> > +};
> > +module_platform_driver(sunxips2_of_driver);
> > +
> > +MODULE_AUTHOR("Aaron.maoye<leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org, "
> > + "Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
>
> Usually, you define two MODULE_AUTHOR.
>
> Okie
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux, Kernel and Android engineering
> http://free-electrons.com
>
--
You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
[-- Attachment #2: Type: text/html, Size: 25940 bytes --]
^ permalink raw reply
* Re: Disable input device
From: Chuck Ebbert @ 2014-12-06 15:28 UTC (permalink / raw)
To: Pali Rohár
Cc: Dmitry Torokhov, Sebastian Reichel, Pavel Machek, kernel list,
linux-input, Henrik Rydberg
In-Reply-To: <201411291824.03996@pali>
On Sat, 29 Nov 2014 18:24:03 +0100
Pali Rohár <pali.rohar@gmail.com> wrote:
> What do you think about adding new sysfs file "disable" (accept
> values 1 or 0) for every input device? With "1" it cause that
> kernel will drop all events from specific input device and if
> driver provide some function is can be called (e.g. for power
> management or disabling device at hardware level).
>
Yeah, I'd like to see this too. I am using xinput to disable the
notebook keyboard so the cats walking across it don't cause any
problems. It would be nice to have a better solution.
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] Input: gpio_keys - initialize the 'irq' variable
From: Fabio Estevam @ 2014-12-06 15:43 UTC (permalink / raw)
To: dmitry.torokhov; +Cc: alexander.stein, linux-input, Fabio Estevam
From: Fabio Estevam <fabio.estevam@freescale.com>
Commit f2d347ff70be453e ("Input: gpio_keys - add device tree support for
interrupt only keys") caused the following build warning:
drivers/input/keyboard/gpio_keys.c: In function 'gpio_keys_probe':
drivers/input/keyboard/gpio_keys.c:647:15: warning: 'irq' may be used uninitialized in this function [-Wmaybe-uninitialized]
drivers/input/keyboard/gpio_keys.c:622:7: note: 'irq' was declared here
Initialize 'irq' with a default value to fix it.
Reported-by: Olof's autobuilder <build@lixom.net>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
---
drivers/input/keyboard/gpio_keys.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index aa13055..70e89d1 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -619,7 +619,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
i = 0;
for_each_child_of_node(node, pp) {
int gpio = -1;
- int irq;
+ int irq = -EINVAL;
enum of_gpio_flags flags;
if (!of_find_property(pp, "gpios", NULL)) {
--
1.9.1
^ permalink raw reply related
* [PATCHv2 0/3] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: vishnupatekar @ 2014-12-06 23:15 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-lFZ/pmaqli7XmaaqVzeoHQ
Cc: leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA, vishnupatekar
Here is v2 of SUNXI PS2 controller support patch-set as with v1.
Changes in v2:
1. added default n depends on ARCH_SUNXI || COMPILE_TEST in Kconfig.
2. handled errors and free resources on errors.
3. used BIT(x), DIV_ROUND_UP macros.
4. corrected style errors.
5. added support for A10 also, A10 and A2 have same properties of PS2 controller.
6. by default commented ps20 and ps21 nodes,as ps20 pins conflict with HDMI
connector on Lime2 Board.
7. added compatible as allwinner,sun4i-a10-ps2.
8. corrected the possible race condition.
Patch 0 Summary: Allwinner A10/A20 PS2 controller. These modifications are
for PS2 host controller. IBM compliant IBM PS2 and AT-compatible
keyboard and mouse can be connected.
Patch 1 device tree bindings.
Patch 2 adds support for sun7i ps2 driver.
Patch 3 device tree support for PS2 controller.
1) Added A10/A20 ps2 nodes to the dtsi
2) Added A10/A20 ps2 pinmux to the dtsi
3) Added ps2 nodes to the lime2 dts file
vishnupatekar (3):
sunxi:dts-bindings:input:ps2 bindings for A10/A20 ps2.
sunxi:drivers:input:ps2 Added sunxi A10/A20 ps2 driver
ARM:dts:sunxi:ps2 dt nodes for A10/A20 PS2 controller.
.../bindings/input/allwinner,sunxi-ps2.txt | 23 ++
arch/arm/boot/dts/sun4i-a10.dtsi | 27 ++
arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts | 13 +
arch/arm/boot/dts/sun7i-a20.dtsi | 29 ++
drivers/input/serio/Kconfig | 10 +
drivers/input/serio/Makefile | 1 +
drivers/input/serio/sunxi-ps2.c | 364 ++++++++++++++++++++
7 files changed, 467 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
create mode 100644 drivers/input/serio/sunxi-ps2.c
--
1.7.9.5
^ permalink raw reply
* [PATCHv2 1/3] sunxi:dts-bindings:input:ps2 bindings for A10/A20 ps2.
From: vishnupatekar @ 2014-12-06 23:15 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-lFZ/pmaqli7XmaaqVzeoHQ
Cc: leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA, vishnupatekar
In-Reply-To: <1417907719-26775-1-git-send-email-VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
A10 and A20 have same PS2 addresses, clocks, interrupts.
added compatible as allwinner,sun4i-a10-ps2.
Signed-off-by: vishnupatekar <VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
.../bindings/input/allwinner,sunxi-ps2.txt | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
diff --git a/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt b/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
new file mode 100644
index 0000000..3a8919a
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
@@ -0,0 +1,23 @@
+* Device tree bindings for Allwinner A10, A20 PS2 host controller
+
+A20 PS2 is dual role controller(PS2 host and PS2 device). These bindings are for PS2 host controller.
+IBM compliant IBM PS2 and AT-compatible keyboard and mouse can be connected.
+
+Required properties:
+
+ - reg : Offset and length of the register set for the device.
+ - compatible : Should one of the following:
+ - "allwinner,sun7i-a20-ps2"
+ - "allwinner,sun4i-a10-ps2"
+ - interrupts : The interrupt line connected to the PS2.
+ - clocks : The gate clk connected to the PS2.
+
+
+Example:
+ ps20: ps2@0x01c2a000 {
+ compatible = "allwinner,sun7i-a20-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <0 62 4>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
--
1.7.9.5
^ permalink raw reply related
* [PATCHv2 2/3] sunxi:drivers:input:ps2 Added sunxi A10/A20 ps2 driver
From: vishnupatekar @ 2014-12-06 23:15 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-lFZ/pmaqli7XmaaqVzeoHQ
Cc: leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA, vishnupatekar
In-Reply-To: <1417907719-26775-1-git-send-email-VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
-added compatible as allwinner,sun4i-a10-ps2 and allwinner,sun7i-a20-ps2.
- added default n depends on ARCH_SUNXI || COMPILE_TEST
in Kconfig.
-handled errors and free resources on errors.
-used BIT(x), DIV_ROUND_UP macros.
-corrected style errors.
Signed-off-by: vishnupatekar <VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/input/serio/Kconfig | 10 ++
drivers/input/serio/Makefile | 1 +
drivers/input/serio/sunxi-ps2.c | 364 +++++++++++++++++++++++++++++++++++++++
3 files changed, 375 insertions(+)
create mode 100644 drivers/input/serio/sunxi-ps2.c
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bc2d474..3a7599c 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -281,4 +281,14 @@ config HYPERV_KEYBOARD
To compile this driver as a module, choose M here: the module will
be called hyperv_keyboard.
+config SERIO_SUNXI_PS2
+ tristate "Allwinner Sun4i-A10/Sun7i-A20 PS/2 controller"
+ default n
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ Say Y here if you have Sun4i-A10/Sun7i-A20 Allwinner PS/2 ports.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sunxi-ps2.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 815d874..0fa0f78 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
+obj-$(CONFIG_SERIO_SUNXI_PS2) += sunxi-ps2.o
diff --git a/drivers/input/serio/sunxi-ps2.c b/drivers/input/serio/sunxi-ps2.c
new file mode 100644
index 0000000..4cd89ae
--- /dev/null
+++ b/drivers/input/serio/sunxi-ps2.c
@@ -0,0 +1,364 @@
+/*
+ * Driver for Allwinner A20 PS2 host controller
+ *
+ * Author: Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>
+ *
+ * Based on 3.0 kernel
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+
+#define DRIVER_NAME "sunxi-ps2"
+
+/* register offset definitions */
+#define PS2_REG_GCTL (0x00) /* PS2 Module Global Control Reg */
+#define PS2_REG_DATA (0x04) /* PS2 Module Data Reg */
+#define PS2_REG_LCTL (0x08) /* PS2 Module Line Control Reg */
+#define PS2_REG_LSTS (0x0C) /* PS2 Module Line Status Reg */
+#define PS2_REG_FCTL (0x10) /* PS2 Module FIFO Control Reg */
+#define PS2_REG_FSTS (0x14) /* PS2 Module FIFO Status Reg */
+#define PS2_REG_CLKDR (0x18) /* PS2 Module Clock Divider Reg*/
+
+/* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
+#define PS2_GCTL_INTFLAG BIT(4)
+#define PS2_GCTL_INTEN BIT(3)
+#define PS2_GCTL_RESET BIT(2)
+#define PS2_GCTL_MASTER BIT(1)
+#define PS2_GCTL_BUSEN BIT(0)
+
+/* PS2 LINE CONTROL REGISTER */
+#define PS2_LCTL_NOACK BIT(18)
+#define PS2_LCTL_TXDTOEN BIT(8)
+#define PS2_LCTL_STOPERREN BIT(3)
+#define PS2_LCTL_ACKERREN BIT(2)
+#define PS2_LCTL_PARERREN BIT(1)
+#define PS2_LCTL_RXDTOEN BIT(0)
+
+/* PS2 LINE STATUS REGISTER */
+#define PS2_LSTS_TXTDO BIT(8)
+#define PS2_LSTS_STOPERR BIT(3)
+#define PS2_LSTS_ACKERR BIT(2)
+#define PS2_LSTS_PARERR BIT(1)
+#define PS2_LSTS_RXTDO BIT(0)
+
+/* PS2 FIFO CONTROL REGISTER */
+#define PS2_FCTL_TXRST BIT(17)
+#define PS2_FCTL_RXRST BIT(16)
+#define PS2_FCTL_TXUFIEN BIT(10)
+#define PS2_FCTL_TXOFIEN BIT(9)
+#define PS2_FCTL_TXRDYIEN BIT(8)
+#define PS2_FCTL_RXUFIEN BIT(2)
+#define PS2_FCTL_RXOFIEN BIT(1)
+#define PS2_FCTL_RXRDYIEN BIT(0)
+
+/* PS2 FIFO STATUS REGISTER */
+#define PS2_FSTS_TXUF BIT(10)
+#define PS2_FSTS_TXOF BIT(9)
+#define PS2_FSTS_TXRDY BIT(8)
+#define PS2_FSTS_RXUF BIT(2)
+#define PS2_FSTS_RXOF BIT(1)
+#define PS2_FSTS_RXRDY BIT(0)
+
+
+#define PS2_LINE_ERROR_BIT \
+ (PS2_LSTS_TXTDO|PS2_LSTS_STOPERR|PS2_LSTS_ACKERR| \
+ PS2_LSTS_PARERR|PS2_LSTS_RXTDO)
+
+#define PS2_FIFO_ERROR_BIT \
+ (PS2_FSTS_TXUF|PS2_FSTS_TXOF|PS2_FSTS_TXRDY|PS2_FSTS_RXUF| \
+ PS2_FSTS_RXOF|PS2_FSTS_RXRDY)
+
+#define PS2_SAMPLE_CLK (1000000)
+#define PS2_SCLK (125000)
+
+struct sunxips2data {
+ struct serio *serio;
+ struct device *dev;
+
+ /* IO mapping base */
+ void __iomem *reg_base;
+
+ /* clock management */
+ struct clk *clk;
+
+ /* irq */
+ spinlock_t lock;
+ int irq;
+};
+
+/*********************/
+/* Interrupt handler */
+/*********************/
+static irqreturn_t sunxips2_interrupt(int irq, void *dev_id)
+{
+ struct sunxips2data *drvdata = dev_id;
+ u32 intr_status;
+ u32 fifo_status;
+ unsigned char byte;
+ u32 rval;
+ u32 error = 0;
+
+ spin_lock(&drvdata->lock);
+
+ /* Get the PS/2 interrupts and clear them */
+ intr_status = readl(drvdata->reg_base + PS2_REG_LSTS);
+ fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS);
+
+ /*Check Line Status Register*/
+ if (intr_status & 0x10f) {
+ if (intr_status & PS2_LSTS_STOPERR)
+ dev_info(drvdata->dev, "PS/2 Stop Bit Error!");
+ if (intr_status & PS2_LSTS_ACKERR)
+ dev_info(drvdata->dev, "PS/2 Acknowledge Error!\n");
+ if (intr_status & PS2_LSTS_PARERR)
+ dev_info(drvdata->dev, "PS/2 Parity Error!\n");
+ if (intr_status & PS2_LSTS_TXTDO)
+ dev_info(drvdata->dev, "PS/2 Transmit Data Timeout!\n");
+ if (intr_status & PS2_LSTS_RXTDO)
+ dev_info(drvdata->dev, "PS/2 Receive Data Timeout!\n");
+
+ /*reset PS/2 controller*/
+ writel(readl(drvdata->reg_base + PS2_REG_GCTL) | PS2_GCTL_RESET,
+ drvdata->reg_base + PS2_REG_GCTL);
+
+ rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
+ PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
+ writel(rval, drvdata->reg_base + PS2_REG_LSTS);
+ error = 1;
+ }
+
+ /*Check FIFO Status Register*/
+ if (fifo_status & 0x0606) {
+ if (fifo_status & PS2_FSTS_TXUF)
+ dev_info(drvdata->dev, "PS/2 Tx FIFO Underflow!\n");
+ if (fifo_status & PS2_FSTS_TXOF)
+ dev_info(drvdata->dev, "PS/2 Tx FIFO Overflow!\n");
+ if (fifo_status & PS2_FSTS_RXUF)
+ dev_info(drvdata->dev, "PS/2 Rx FIFO Underflow!\n");
+ if (fifo_status & PS2_FSTS_RXOF)
+ dev_info(drvdata->dev, "PS/2 Rx FIFO Overflow!\n");
+ /*reset PS/2 controller*/
+ writel(readl(drvdata->reg_base + PS2_REG_GCTL) | PS2_GCTL_RESET,
+ drvdata->reg_base + PS2_REG_GCTL);
+
+ rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
+ PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
+ writel(rval, drvdata->reg_base + PS2_REG_FSTS);
+ error = 1;
+ }
+
+ rval = (fifo_status >> 16) & 0x3;
+ while (!error && rval--) {
+ byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
+ /* dev_info(drvdata->dev, "PS/2 Receive %02x\n", byte); */
+ serio_interrupt(drvdata->serio, byte, 0);
+ }
+
+ writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
+ writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
+
+ spin_unlock(&drvdata->lock);
+
+ return IRQ_HANDLED;
+}
+
+
+static int sunxips2_open(struct serio *pserio)
+{
+ struct sunxips2data *drvdata = pserio->port_data;
+ u32 src_clk = 0;
+ u32 clk_scdf;
+ u32 clk_pcdf;
+ u32 rval;
+
+ /*Set Line Control And Enable Interrupt*/
+ rval = PS2_LCTL_TXDTOEN | PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
+ | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
+ writel(rval, drvdata->reg_base + PS2_REG_LCTL);
+
+ /*Reset FIFO*/
+ rval = PS2_FCTL_TXRST|PS2_FCTL_RXRST|PS2_FCTL_TXUFIEN|PS2_FCTL_TXOFIEN
+ |PS2_FCTL_RXUFIEN|PS2_FCTL_RXOFIEN|PS2_FCTL_RXRDYIEN;
+ writel(rval, drvdata->reg_base + PS2_REG_FCTL);
+
+ src_clk = clk_get_rate(drvdata->clk);
+
+ if (!src_clk) {
+ dev_info(drvdata->dev, "w_ps2c_set_sclk error, source clock is 0.");
+ return -1;
+ }
+
+ /*Set Clock Divider Register*/
+ clk_scdf = DIV_ROUND_UP(src_clk, PS2_SAMPLE_CLK) - 1;
+ clk_pcdf = DIV_ROUND_UP(PS2_SAMPLE_CLK, PS2_SCLK) - 1;
+ rval = (clk_scdf<<8) | clk_pcdf;
+ writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
+
+ /*Set Global Control Register*/
+ rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
+ | PS2_GCTL_BUSEN;
+ writel(rval, drvdata->reg_base + PS2_REG_GCTL);
+
+ return 0;
+}
+
+static void sunxips2_close(struct serio *pserio)
+{
+ struct sunxips2data *drvdata = pserio->port_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+ /* Disable the PS2 interrupts */
+ writel(0, drvdata->reg_base + PS2_REG_GCTL);
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+}
+
+static int sunxips2_write(struct serio *pserio, unsigned char val)
+{
+ unsigned long expire = jiffies + msecs_to_jiffies(10000);
+ struct sunxips2data *drvdata = (struct sunxips2data *)pserio->port_data;
+
+ do {
+ if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
+ writel(val, drvdata->reg_base + PS2_REG_DATA);
+ return 0;
+ }
+ } while (time_before(jiffies, expire));
+
+ return 0;
+}
+
+static int sunxips2_probe(struct platform_device *pdev)
+{
+ struct resource *res; /* IO mem resources */
+ struct sunxips2data *drvdata;
+ struct serio *serio;
+ struct device *dev = &pdev->dev;
+ unsigned int irq;
+ int error;
+
+ drvdata = devm_kzalloc(dev, sizeof(struct sunxips2data), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!drvdata || !serio) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ spin_lock_init(&drvdata->lock);
+
+ /* IO */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drvdata->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(drvdata->reg_base)) {
+ dev_err(dev, "failed to map registers\n");
+ error = PTR_ERR(drvdata->reg_base);
+ goto err_free_mem;
+ }
+
+ drvdata->clk = devm_clk_get(dev, NULL);
+ if (!IS_ERR(drvdata->clk)) {
+ error = clk_prepare_enable(drvdata->clk);
+ if (error < 0) {
+ dev_err(dev, "failed to enable clock %d\n", error);
+ goto err_free_mem;
+ }
+ } else {
+ error = PTR_ERR(drvdata->clk);
+ dev_err(dev, "couldn't get clock %d\n", error);
+ goto err_free_mem;
+ }
+
+ serio->id.type = SERIO_8042;
+ serio->write = sunxips2_write;
+ serio->open = sunxips2_open;
+ serio->close = sunxips2_close;
+ serio->port_data = drvdata;
+ serio->dev.parent = dev;
+ strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
+ strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
+
+ /* Get IRQ for the device */
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(dev, "no IRQ found\n");
+ error = -ENXIO;
+ goto error_disable_clk;
+ }
+
+ drvdata->irq = irq;
+ drvdata->serio = serio;
+ drvdata->dev = dev;
+ error = devm_request_threaded_irq(dev, drvdata->irq,
+ sunxips2_interrupt, NULL, 0, DRIVER_NAME, drvdata);
+
+ if (error) {
+ dev_err(drvdata->dev, "Interrupt alloc failed %d:error:%d\n",
+ drvdata->irq, error);
+ goto error_disable_clk;
+ }
+
+ serio_register_port(serio);
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0; /* success */
+
+error_disable_clk:
+ clk_disable_unprepare(drvdata->clk);
+
+err_free_mem:
+ kfree(serio);
+ return error;
+}
+
+static int sunxips2_remove(struct platform_device *pdev)
+{
+ struct sunxips2data *drvdata = platform_get_drvdata(pdev);
+
+ serio_unregister_port(drvdata->serio);
+ disable_irq(drvdata->irq);
+
+ if (!IS_ERR(drvdata->clk))
+ clk_disable_unprepare(drvdata->clk);
+ kfree(drvdata->serio);
+
+ return 0;
+}
+
+/* Match table for of_platform binding */
+static const struct of_device_id sunxips2_of_match[] = {
+ { .compatible = "allwinner,sun7i-a20-ps2", },
+ { .compatible = "allwinner,sun4i-a10-ps2", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, sunxips2_of_match);
+
+/*platform driver structure*/
+static struct platform_driver sunxips2_of_driver = {
+ .probe = sunxips2_probe,
+ .remove = sunxips2_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = sunxips2_of_match,
+ },
+};
+module_platform_driver(sunxips2_of_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_AUTHOR("Aaron.maoye <leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ@public.gmane.org>");
+MODULE_DESCRIPTION("Sunxi PS/2 driver");
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
* [PATCHv2 3/3] ARM:dts:sunxi:ps2 dt nodes for A10/A20 PS2 controller.
From: vishnupatekar @ 2014-12-06 23:15 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-lFZ/pmaqli7XmaaqVzeoHQ
Cc: leafy.myeh-Q9AEpCAkrSgqDJ6do+/SaQ, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-input-u79uwXL29TY76Z2rM5mHXA, vishnupatekar
In-Reply-To: <1417907719-26775-1-git-send-email-VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Added ps2 nodes in lime2 board dts. By default ps20 and ps21 nodes are
commented as ps20 pins conflict with HDMI connector
on Lime2 Board.
Signed-off-by: vishnupatekar <VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 27 +++++++++++++++++++++
arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts | 13 ++++++++++
arch/arm/boot/dts/sun7i-a20.dtsi | 29 +++++++++++++++++++++++
3 files changed, 69 insertions(+)
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 5e2ec2d..4726e8d 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -615,6 +615,19 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+ ps2_0_pins: ps2_0@0 {
+ allwinner,pins = "PI20","PI21";
+ allwinner,function = "ps2";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ ps2_1_pins: ps2_1@0 {
+ allwinner,pins = "PH12","PH13";
+ allwinner,function = "ps2";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
};
timer@01c20c00 {
@@ -781,5 +794,19 @@
#address-cells = <1>;
#size-cells = <0>;
};
+ ps20: ps2@0x01c2a000 {
+ compatible = "allwinner,sun4i-a10-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <0 62 4>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
+ ps21: ps2@0x01c2a400 {
+ compatible = "allwinner,sun4i-a10-ps2";
+ reg = <0x01c2a400 0x400>;
+ interrupts = <0 63 4>;
+ clocks = <&apb1_gates 7>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index ed364d5..5624e63 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -112,6 +112,19 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+ /* PS2 0 and PS2 1 are disabled by default
+ To enable PS2 0 and PS2 1 uncomment below ps20 and ps21 nodes
+ Please note that ps20 pins conflict with HDMI on Lime2 Board*/
+ /*ps20: ps2@0x01c2a000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ps2_0_pins>;
+ status = "okay";
+ };
+ ps21: ps2@0x01c2a400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ps2_1_pins>;
+ status = "okay";
+ };*/
i2c0: i2c@01c2ac00 {
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 8605f2b..96fe37d 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -852,6 +852,19 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+ ps2_0_pins: ps2_0@0 {
+ allwinner,pins = "PI20","PI21";
+ allwinner,function = "ps2";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ ps2_1_pins: ps2_1@0 {
+ allwinner,pins = "PH12","PH13";
+ allwinner,function = "ps2";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
};
timer@01c20c00 {
@@ -1079,5 +1092,21 @@
#interrupt-cells = <3>;
interrupts = <1 9 0xf04>;
};
+ ps20: ps2@0x01c2a000 {
+ compatible = "allwinner,sun7i-a20-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <0 62 4>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
+ ps21: ps2@0x01c2a400 {
+ compatible = "allwinner,sun7i-a20-ps2";
+ reg = <0x01c2a400 0x400>;
+ interrupts = <0 63 4>;
+ clocks = <&apb1_gates 7>;
+ status = "disabled";
+ };
+
+
};
};
--
1.7.9.5
^ permalink raw reply related
* PROBLEM: [HP Stream Notebook - 11-d010nr] clickpad malfunctions after performing a hardware click
From: Amordea Whiteoak @ 2014-12-07 22:50 UTC (permalink / raw)
To: linux-input
Original Bug Report:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1398533
Bug Description: After clicking once at the bottom of my clickpad on
either button, if I move my cursor elsewhere on the screen, and then
subsequently click again (with either clickpad or external mouse this
time) it registers a click at the location where my cursor icon was
originally. I can continue to move my cursor anywhere on the screen,
and it still registers the click in the original location.
cat /proc/version
Linux version 3.18.0-031800rc7-generic (apw@gomeisa) (gcc version
4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) ) #201411302035 SMP Mon Dec 1
01:36:38 UTC 2014
lsb_release -rd
Description: Ubuntu 14.10
Release: 14.10
sh /usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
Linux woprjr 3.18.0-031800rc7-generic #201411302035 SMP Mon Dec 1
01:36:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
Gnu C
/usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux:
/usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux: 20:
/usr/src/linux-headers-3.18.0-031800rc7/scripts/ver_linux: ld: not
found
binutils
util-linux 2.25.1
mount debug
module-init-tools 18
e2fsprogs 1.42.10
PPP 2.4.5
Linux C Library 2.19
Dynamic linker (ldd) 2.19
Procps 3.3.9
Net-tools 1.60
Kbd 1.15.5
Sh-utils 8.23
wireless-tools 30
Modules Loaded snd_hda_codec_hdmi snd_hda_codec_realtek
snd_hda_codec_generic ctr ccm joydev hp_wmi hid_rmi sparse_keymap
rfcomm bnep arc4 rtl8723be btcoexist rtl8723_common intel_rapl
uvcvideo rtl_pci intel_soc_dts_thermal intel_powerclamp
videobuf2_vmalloc videobuf2_memops coretemp rtlwifi videobuf2_core
v4l2_common videodev mac80211 media kvm cfg80211 btusb
crct10dif_pclmul crc32_pclmul bluetooth ghash_clmulni_intel serio_raw
cryptd wmi snd_hda_intel snd_hda_controller snd_hda_codec snd_hwdep
snd_seq_midi snd_seq_midi_event snd_rawmidi snd_soc_rt5640
snd_soc_rl6231 snd_soc_core snd_compress dw_dmac i915
snd_pcm_dmaengine dw_dmac_core snd_seq int3400_thermal int3403_thermal
acpi_thermal_rel nls_iso8859_1 snd_pcm i2c_hid video
intel_smartconnect drm_kms_helper hid drm rfkill_gpio snd_seq_device
i2c_designware_platform i2c_algo_bit snd_soc_sst_acpi 8250_dw
snd_timer i2c_designware_core hp_wireless shpchp spi_pxa2xx_platform
snd pwm_lpss_platform lpc_ich mac_hid mei_txe pwm_lpss iosf_mbi mei
soundcore parport_pc ppdev lp parport uas usb_storage mmc_block
sdhci_acpi sdhci
cat /proc/cpuinfo
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 55
model name : Intel(R) Celeron(R) CPU N2840 @ 2.16GHz
stepping : 8
microcode : 0x829
cpu MHz : 499.741
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 11
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology
nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2
ssse3 cx16 xtpr pdcm sse4_1 sse4_2 movbe popcnt tsc_deadline_timer
rdrand lahf_lm 3dnowprefetch ida arat epb dtherm tpr_shadow vnmi
flexpriority ept vpid tsc_adjust smep erms
bugs :
bogomips : 4326.40
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 55
model name : Intel(R) Celeron(R) CPU N2840 @ 2.16GHz
stepping : 8
microcode : 0x829
cpu MHz : 499.741
cache size : 1024 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 2
initial apicid : 2
fpu : yes
fpu_exception : yes
cpuid level : 11
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx
rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology
nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2
ssse3 cx16 xtpr pdcm sse4_1 sse4_2 movbe popcnt tsc_deadline_timer
rdrand lahf_lm 3dnowprefetch ida arat epb dtherm tpr_shadow vnmi
flexpriority ept vpid tsc_adjust smep erms
bugs :
bogomips : 4326.40
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
cat /proc/modules
snd_hda_codec_hdmi 52670 1 - Live 0x0000000000000000
snd_hda_codec_realtek 80420 1 - Live 0x0000000000000000
snd_hda_codec_generic 69995 1 snd_hda_codec_realtek, Live 0x0000000000000000
ctr 13193 1 - Live 0x0000000000000000
ccm 17856 1 - Live 0x0000000000000000
joydev 17587 0 - Live 0x0000000000000000
hp_wmi 14017 0 - Live 0x0000000000000000
hid_rmi 18060 0 - Live 0x0000000000000000
sparse_keymap 13890 1 hp_wmi, Live 0x0000000000000000
rfcomm 75066 8 - Live 0x0000000000000000
bnep 23980 2 - Live 0x0000000000000000
arc4 12573 2 - Live 0x0000000000000000
rtl8723be 96097 0 - Live 0x0000000000000000
btcoexist 51822 1 rtl8723be, Live 0x0000000000000000
rtl8723_common 23662 1 rtl8723be, Live 0x0000000000000000
intel_rapl 19196 0 - Live 0x0000000000000000
uvcvideo 86723 0 - Live 0x0000000000000000
rtl_pci 27417 1 rtl8723be, Live 0x0000000000000000
intel_soc_dts_thermal 13523 0 - Live 0x0000000000000000
intel_powerclamp 19099 0 - Live 0x0000000000000000
videobuf2_vmalloc 13216 1 uvcvideo, Live 0x0000000000000000
videobuf2_memops 13362 1 videobuf2_vmalloc, Live 0x0000000000000000
coretemp 13638 0 - Live 0x0000000000000000
rtlwifi 74744 2 rtl8723be,rtl_pci, Live 0x0000000000000000
videobuf2_core 51547 1 uvcvideo, Live 0x0000000000000000
v4l2_common 15715 1 videobuf2_core, Live 0x0000000000000000
videodev 163831 3 uvcvideo,videobuf2_core,v4l2_common, Live 0x0000000000000000
mac80211 697159 3 rtl8723be,rtl_pci,rtlwifi, Live 0x0000000000000000
media 22008 2 uvcvideo,videodev, Live 0x0000000000000000
kvm 475237 0 - Live 0x0000000000000000
cfg80211 520257 2 rtlwifi,mac80211, Live 0x0000000000000000
btusb 32691 0 - Live 0x0000000000000000
crct10dif_pclmul 14268 0 - Live 0x0000000000000000
crc32_pclmul 13180 0 - Live 0x0000000000000000
bluetooth 486890 22 rfcomm,bnep,btusb, Live 0x0000000000000000
ghash_clmulni_intel 13230 0 - Live 0x0000000000000000
serio_raw 13483 0 - Live 0x0000000000000000
cryptd 20531 1 ghash_clmulni_intel, Live 0x0000000000000000
wmi 19379 1 hp_wmi, Live 0x0000000000000000
snd_hda_intel 30824 1 - Live 0x0000000000000000
snd_hda_controller 32234 1 snd_hda_intel, Live 0x0000000000000000
snd_hda_codec 144641 5
snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel,snd_hda_controller,
Live 0x0000000000000000
snd_hwdep 17709 1 snd_hda_codec, Live 0x0000000000000000
snd_seq_midi 13564 0 - Live 0x0000000000000000
snd_seq_midi_event 14899 1 snd_seq_midi, Live 0x0000000000000000
snd_rawmidi 31197 1 snd_seq_midi, Live 0x0000000000000000
snd_soc_rt5640 93325 0 - Live 0x0000000000000000
snd_soc_rl6231 13037 1 snd_soc_rt5640, Live 0x0000000000000000
snd_soc_core 207780 1 snd_soc_rt5640, Live 0x0000000000000000
snd_compress 19395 1 snd_soc_core, Live 0x0000000000000000
dw_dmac 12835 0 - Live 0x0000000000000000
i915 1031996 2 - Live 0x0000000000000000
snd_pcm_dmaengine 15229 1 snd_soc_core, Live 0x0000000000000000
dw_dmac_core 28558 1 dw_dmac, Live 0x0000000000000000
snd_seq 63540 2 snd_seq_midi,snd_seq_midi_event, Live 0x0000000000000000
int3400_thermal 13040 0 - Live 0x0000000000000000
int3403_thermal 13255 0 - Live 0x0000000000000000
acpi_thermal_rel 13807 1 int3400_thermal, Live 0x0000000000000000
nls_iso8859_1 12713 2 - Live 0x0000000000000000
snd_pcm 106273 7
snd_hda_codec_hdmi,snd_hda_intel,snd_hda_controller,snd_hda_codec,snd_soc_rt5640,snd_soc_core,snd_pcm_dmaengine,
Live 0x0000000000000000
i2c_hid 19065 0 - Live 0x0000000000000000
video 20649 1 i915, Live 0x0000000000000000
intel_smartconnect 12637 0 - Live 0x0000000000000000
drm_kms_helper 99802 1 i915, Live 0x0000000000000000
hid 110572 2 hid_rmi,i2c_hid, Live 0x0000000000000000
drm 323675 4 i915,drm_kms_helper, Live 0x0000000000000000
rfkill_gpio 12761 0 - Live 0x0000000000000000
snd_seq_device 14497 3 snd_seq_midi,snd_rawmidi,snd_seq, Live 0x0000000000000000
i2c_designware_platform 13025 0 - Live 0x0000000000000000
i2c_algo_bit 13564 1 i915, Live 0x0000000000000000
snd_soc_sst_acpi 13007 0 - Live 0x0000000000000000
8250_dw 13474 0 - Live 0x0000000000000000
snd_timer 30118 2 snd_seq,snd_pcm, Live 0x0000000000000000
i2c_designware_core 14990 1 i2c_designware_platform, Live 0x0000000000000000
hp_wireless 12637 0 - Live 0x0000000000000000
shpchp 37216 0 - Live 0x0000000000000000
spi_pxa2xx_platform 23256 0 - Live 0x0000000000000000
snd 84025 15 snd_hda_codec_hdmi,snd_hda_codec_realtek,snd_hda_codec_generic,snd_hda_intel,snd_hda_codec,snd_hwdep,snd_rawmidi,snd_soc_core,snd_compress,snd_seq,snd_pcm,snd_seq_device,snd_timer,
Live 0x0000000000000000
pwm_lpss_platform 12703 0 - Live 0x0000000000000000
lpc_ich 21176 0 - Live 0x0000000000000000
mac_hid 13275 0 - Live 0x0000000000000000
mei_txe 19808 0 - Live 0x0000000000000000
pwm_lpss 13281 1 pwm_lpss_platform, Live 0x0000000000000000
iosf_mbi 13865 1 intel_soc_dts_thermal, Live 0x0000000000000000
mei 88473 1 mei_txe, Live 0x0000000000000000
soundcore 15091 2 snd_hda_codec,snd, Live 0x0000000000000000
parport_pc 32909 0 - Live 0x0000000000000000
ppdev 17711 0 - Live 0x0000000000000000
lp 17799 0 - Live 0x0000000000000000
parport 42481 3 parport_pc,ppdev,lp, Live 0x0000000000000000
uas 22673 0 - Live 0x0000000000000000
usb_storage 67010 2 uas, Live 0x0000000000000000
mmc_block 36596 4 - Live 0x0000000000000000
sdhci_acpi 13502 0 - Live 0x0000000000000000
sdhci 43929 1 sdhci_acpi, Live 0x0000000000000000
/proc/ioports
0000-006f : PCI Bus 0000:00
0000-001f : dma1
0020-0021 : pic1
0040-0043 : timer0
0050-0053 : timer1
0060-0060 : keyboard
0062-0062 : PNP0C09:00
0062-0062 : EC data
0064-0064 : keyboard
0066-0066 : PNP0C09:00
0066-0066 : EC cmd
0070-0077 : rtc0
0078-0cf7 : PCI Bus 0000:00
0080-008f : dma page reg
00a0-00a1 : pic2
00c0-00df : dma2
00f0-00ff : fpu
03f8-03ff : serial
0400-047f : pnp 00:01
0400-0403 : ACPI PM1a_EVT_BLK
0404-0405 : ACPI PM1a_CNT_BLK
0408-040b : ACPI PM_TMR
0420-042f : ACPI GPE0_BLK
0430-0433 : iTCO_wdt
0450-0450 : ACPI PM2_CNT_BLK
0460-047f : iTCO_wdt
0500-05fe : pnp 00:01
0600-061f : pnp 00:01
0680-069f : pnp 00:01
0cf8-0cff : PCI conf1
0d00-ffff : PCI Bus 0000:00
1000-1fff : PCI Bus 0000:01
1000-10ff : 0000:01:00.0
1000-10ff : rtl_pci
2000-201f : 0000:00:1f.3
2050-2057 : 0000:00:02.0
cat /proc/iomem
00000000-00000fff : reserved
00001000-0006efff : System RAM
0006f000-0006ffff : ACPI Non-volatile Storage
00070000-00084fff : System RAM
00085000-00086fff : reserved
00087000-00087fff : System RAM
00088000-0009ffff : reserved
000a0000-000bffff : PCI Bus 0000:00
000c0000-000dffff : PCI Bus 0000:00
000e0000-000fffff : PCI Bus 0000:00
000f0000-000fffff : System ROM
00100000-1effffff : System RAM
02000000-027b8537 : Kernel code
027b8538-02d2123f : Kernel data
02e87000-02fcffff : Kernel bss
1f000000-1f0fffff : reserved
1f100000-1fffffff : System RAM
20000000-200fffff : reserved
20100000-75867fff : System RAM
75868000-75892fff : reserved
75893000-78892fff : System RAM
78893000-78922fff : reserved
78923000-791a3fff : reserved
791a4000-792a2fff : ACPI Non-volatile Storage
792a3000-792e2fff : ACPI Tables
792e3000-79ffffff : System RAM
7a000000-7affffff : RAM buffer
7b000000-7effffff : reserved
7b000000-7effffff : Graphics Stolen Memory
80000000-907ffffe : PCI Bus 0000:00
80000000-8fffffff : 0000:00:02.0
90000000-903fffff : 0000:00:02.0
90400000-904fffff : PCI Bus 0000:01
90400000-90403fff : 0000:01:00.0
90400000-90403fff : rtl_pci
90500000-905fffff : 0000:00:1a.0
90500000-905fffff : mei_txe
90600000-906fffff : 0000:00:1a.0
90600000-906fffff : mei_txe
90700000-9070ffff : 0000:00:14.0
90700000-9070ffff : xhci-hcd
90710000-90713fff : 0000:00:1b.0
90710000-90713fff : ICH HD audio
90718000-9071801f : 0000:00:1f.3
90800000-90800fff : 80860F14:01
90800000-90800fff : 80860F14:01
90803000-90803fff : 80860F41:00
90803000-90803fff : 80860F41:00
90804000-90807fff : INTL9C60:01
90804000-90807fff : INTL9C60:01
90c00000-90ffffff : PCI Bus 0000:00
e0000000-e3ffffff : PCI MMCONFIG 0000 [bus 00-3f]
e00000d0-e00000db : INT33BD:00
e00f8000-e00f8fff : reserved
fec00000-fec003ff : IOAPIC 0
fed00000-fed003ff : HPET 0
fed00000-fed003ff : PNP0103:00
fed01000-fed01fff : reserved
fed01000-fed01fff : pnp 00:03
fed03000-fed03fff : pnp 00:03
fed03008-fed0300c : iTCO_wdt
fed04000-fed04fff : pnp 00:03
fed05000-fed057ff : INT3401:00
fed08000-fed08fff : pnp 00:03
fed0c000-fed0cfff : INT33FC:00
fed0c000-fed0cfff : INT33FC:00
fed0d000-fed0dfff : INT33FC:01
fed0d000-fed0dfff : INT33FC:01
fed0e000-fed0efff : INT33FC:02
fed0e000-fed0efff : INT33FC:02
fed1c000-fed1cfff : pnp 00:03
fed40000-fed44fff : pnp 00:01
fee00000-feefffff : pnp 00:03
fee00000-fee00fff : Local APIC
fef00000-feffffff : pnp 00:03
ff000000-ffffffff : INT0800:00
ffb80000-ffffffff : reserved
sudo lspci -vvv
00:00.0 Host bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx
Series SoC Transaction Register (rev 0e)
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Kernel driver in use: iosf_mbi_pci
00:02.0 VGA compatible controller: Intel Corporation Atom Processor
Z36xxx/Z37xxx Series Graphics & Display (rev 0e) (prog-if 00 [VGA
controller])
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 263
Region 0: Memory at 90000000 (32-bit, non-prefetchable) [size=4M]
Region 2: Memory at 80000000 (32-bit, prefetchable) [size=256M]
Region 4: I/O ports at 2050 [size=8]
Expansion ROM at <unassigned> [disabled]
Capabilities: [d0] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0300c Data: 4162
Capabilities: [b0] Vendor Specific Information: Len=07 <?>
Kernel driver in use: i915
00:14.0 USB controller: Intel Corporation Atom Processor Z36xxx/Z37xxx
Series USB xHCI (rev 0e) (prog-if 30 [XHCI])
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Interrupt: pin A routed to IRQ 261
Region 0: Memory at 90700000 (64-bit, non-prefetchable) [size=64K]
Capabilities: [70] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=375mA PME(D0-,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [80] MSI: Enable+ Count=1/8 Maskable- 64bit+
Address: 00000000fee0300c Data: 41d1
Kernel driver in use: xhci_hcd
00:1a.0 Encryption controller: Intel Corporation Atom Processor
Z36xxx/Z37xxx Series Trusted Execution Engine (rev 0e)
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 262
Region 0: Memory at 90600000 (32-bit, non-prefetchable) [size=1M]
Region 1: Memory at 90500000 (32-bit, non-prefetchable) [size=1M]
Capabilities: [80] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [a0] MSI: Enable+ Count=1/1 Maskable- 64bit-
Address: fee0300c Data: 4122
Kernel driver in use: mei_txe
00:1b.0 Audio device: Intel Corporation Atom Processor Z36xxx/Z37xxx
Series High Definition Audio Controller (rev 0e)
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx+
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 264
Region 0: Memory at 90710000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [50] Power Management version 2
Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+
Address: 00000000fee0300c Data: 4182
Kernel driver in use: snd_hda_intel
00:1c.0 PCI bridge: Intel Corporation Device 0f48 (rev 0e) (prog-if 00
[Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary=00, secondary=01, subordinate=01, sec-latency=0
I/O behind bridge: 00001000-00001fff
Memory behind bridge: 90400000-904fffff
Prefetchable memory behind bridge: 00000000fff00000-00000000000fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort+ <SERR- <PERR-
BridgeCtl: Parity- SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Express (v2) Root Port (Slot+), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0
ExtTag- RBE+
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd- ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 128 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L0s L1, Exit Latency L0s
<512ns, L1 <4us
ClockPM- Surprise- LLActRep+ BwNot+
LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive+
BWMgmt+ ABWMgmt-
SltCap: AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug- Surprise-
Slot #0, PowerLimit 10.000W; Interlock- NoCompl+
SltCtl: Enable: AttnBtn- PwrFlt- MRL- PresDet- CmdCplt- HPIrq- LinkChg-
Control: AttnInd Unknown, PwrInd Unknown, Power- Interlock-
SltSta: Status: AttnBtn- PowerFlt- MRL- CmdCplt- PresDet+ Interlock-
Changed: MRL- PresDet- LinkState+
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Range BC, TimeoutDis+, LTR-, OBFF Not
Supported ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF
Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance-
ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -3.5dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [80] MSI: Enable- Count=1/1 Maskable- 64bit-
Address: 00000000 Data: 0000
Capabilities: [90] Subsystem: Hewlett-Packard Company Device 8023
Capabilities: [a0] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Kernel driver in use: pcieport
00:1f.0 ISA bridge: Intel Corporation Atom Processor Z36xxx/Z37xxx
Series Power Control Unit (rev 0e)
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0
Capabilities: [e0] Vendor Specific Information: Len=0c <?>
Kernel driver in use: lpc_ich
00:1f.3 SMBus: Intel Corporation Device 0f12 (rev 0e)
Subsystem: Hewlett-Packard Company Device 8023
Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Interrupt: pin B routed to IRQ 255
Region 0: Memory at 90718000 (32-bit, non-prefetchable) [size=32]
Region 4: I/O ports at 2000 [size=32]
Capabilities: [50] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
01:00.0 Network controller: Realtek Semiconductor Co., Ltd. RTL8723BE
PCIe Wireless Network Adapter
Subsystem: Hewlett-Packard Company Device 2231
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort-
<TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 16
Region 0: I/O ports at 1000 [size=256]
Region 2: Memory at 90400000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1+ D2+ AuxCurrent=375mA PME(D0+,D1+,D2+,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Capabilities: [70] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <4us, L1 <64us
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 2.5GT/s, Width x1, ASPM L0s L1, Exit Latency
L0s <512ns, L1 <64us
ClockPM+ Surprise- LLActRep- BwNot-
LnkCtl: ASPM L0s L1 Enabled; RCB 64 bytes Disabled- CommClk+
ExtSynch- ClockPM+ AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 2.5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive-
BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Not Supported, TimeoutDis+, LTR+, OBFF
Via message/WAKE#
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis+, LTR+, OBFF Disabled
LnkCtl2: Target Link Speed: 2.5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance-
ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-,
EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [100 v2] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF-
MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+
MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr+ BadTLP- BadDLLP+ Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 0d, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [140 v1] Device Serial Number 00-23-b7-fe-ff-4c-e0-00
Capabilities: [150 v1] Latency Tolerance Reporting
Max snoop latency: 71680ns
Max no snoop latency: 71680ns
Capabilities: [158 v1] L1 PM Substates
L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
PortCommonModeRestoreTime=150us PortTPowerOnTime=150us
Kernel driver in use: rtl8723be
cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
Vendor: Generic- Model: SD/MMC/MS PRO Rev: 1.00
Type: Direct-Access ANSI SCSI revision: 04
ls /proc
1 12 14 1667 1745 18 1963 2345 292 35 470 55
7201 asound execdomains kmsg pagetypeinfo sysvipc
10 1218 1410 1685 1761 1804 2 2388 296 3573 471 554
728 buddyinfo fb kpagecount partitions thread-self
1020 125 142 1687 1764 1805 20 24 3 359 473 56
755 bus filesystems kpageflags sched_debug timer_list
1025 126 1420 1690 1767 1818 21 25 30 3623 474 57
76 cgroups fs loadavg schedstat timer_stats
1032 127 1423 17 1769 1828 2169 2528 31 378 485 585
77 cmdline interrupts locks scsi tty
1033 128 143 1701 1771 1853 2187 254 3181 3822 5 606
7886 consoles iomem mdstat self uptime
1038 129 1444 1710 1772 1876 2197 26 33 39 509 654
8 cpuinfo ioports meminfo slabinfo version
1042 13 1485 1718 1781 1883 2198 2670 3309 3932 516 655
8743 crypto irq misc softirqs vmallocinfo
1069 130 15 1722 1787 1893 22 2672 34 40 53 695
9 devices kallsyms modules stat vmstat
1070 131 1568 1725 1789 1896 2202 27 3419 41 539 7
9040 diskstats kcore mounts swaps zoneinfo
11 132 1645 1727 1792 19 2248 28 3433 468 542 709
9056 dma keys mtrr sys
1144 1331 1655 1732 1796 1905 23 29 3437 469 5421 715
acpi driver key-users net sysrq-trigger
^ permalink raw reply
* [PATCH] driver: input :touchscreen : add Raydium I2C touch driver
From: jeffrey.lin @ 2014-12-08 3:42 UTC (permalink / raw)
To: dmitry.torokhov, rydberg, shc_work, bleung, lee.jones,
charliemooney
Cc: jeffrey.lin, roger.yang, KP.li, linux-kernel, linux-input
From: "jeffrey.lin" <jeffrey.lin@rad-ic.com>
This patch is porting Raydium I2C touch driver. Developer can enable
raydium touch driver by modifying define "CONFIG_TOUCHSCREEN_RM_TS".
Signed-off-by: jeffrey.lin@rad-ic.com
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/rm31100_ts.c | 846 +++++++++++++++++++++++++++++++++
3 files changed, 859 insertions(+)
create mode 100644 drivers/input/touchscreen/rm31100_ts.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3ce9181..d0324d2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -955,4 +955,16 @@ config TOUCHSCREEN_ZFORCE
To compile this driver as a module, choose M here: the
module will be called zforce_ts.
+config TOUCHSCREEN_RM_TS
+ tristate "Raydium I2C Touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have Raydium series I2C touchscreen,
+ such as RM31100 , connected to your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rm31100_ts.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 687d5a7..3220f66 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -78,3 +78,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o
+obj-$(CONFIG_TOUCHSCREEN_RM_TS) += rm31100_ts.o
diff --git a/drivers/input/touchscreen/rm31100_ts.c b/drivers/input/touchscreen/rm31100_ts.c
new file mode 100644
index 0000000..997dc0c
--- /dev/null
+++ b/drivers/input/touchscreen/rm31100_ts.c
@@ -0,0 +1,846 @@
+/*
+ * Raydium RM31100_ts touchscreen driver.
+ *
+ * Copyright (C) 2012-2014, Raydium Semiconductor Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Raydium reserves the right to make changes without further notice
+ * to the materials described herein. Raydium does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Raydium Semiconductor Corporation at www.rad-ic.com
+ *
+ * History:
+ * (C) 2012 Raydium - Update for GPL distribution
+ * (C) 2009 Enea - Original prototype
+ *
+ */
+#include <linux/async.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#ifdef CONFIG_MISC_DEV
+#include <linux/miscdevice.h>
+#endif
+#include <linux/uaccess.h>
+#include <asm/unaligned.h>
+#include <linux/input/mt.h>
+
+#define rm31100 0x0
+#define rm3110x 0x1
+
+#define INVALID_DATA 0xff
+#define MAX_REPORT_TOUCHED_POINTS 10
+
+#define I2C_CLIENT_ADDR 0x39
+#define I2C_DMA_CLIENT_ADDR 0x5A
+
+struct rm31100_ts_data {
+ u8 x_index;
+ u8 y_index;
+ u8 z_index;
+ u8 id_index;
+ u8 touch_index;
+ u8 data_reg;
+ u8 status_reg;
+ u8 data_size;
+ u8 touch_bytes;
+ u8 update_data;
+ u8 touch_meta_data;
+ u8 finger_size;
+};
+
+struct rm3110x_ts_platform_data {
+ int (*power_on)(int on);
+ int (*dev_setup)(bool on);
+ const char *ts_name;
+ u32 dis_min_x; /* display resoltion ABS min*/
+ u32 dis_max_x;/* display resoltion ABS max*/
+ u32 dis_min_y;
+ u32 dis_max_y;
+ u32 min_touch; /* no.of touches supported */
+ u32 max_touch;
+ u32 min_tid; /* track id */
+ u32 max_tid;
+ u32 min_width;/* size of the finger */
+ u32 max_width;
+ u32 res_x; /* TS resolution unit*/
+ u32 res_y;
+ u32 swap_xy;
+ u8 nfingers;
+ u32 irq_gpio;
+ int resout_gpio;
+ bool wakeup;
+ u32 irq_cfg;
+};
+
+static struct rm31100_ts_data devices[] = {
+ [0] = {
+ .x_index = 2,
+ .y_index = 4,
+ .z_index = 6,
+ .id_index = 1,
+ .data_reg = 0x1,
+ .status_reg = 0,
+ .update_data = 0x0,
+ .touch_bytes = 6,
+ .touch_meta_data = 1,
+ .finger_size = 70,
+ },
+};
+
+struct rm31100_ts {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct rm3110x_ts_platform_data *pdata;
+ struct rm31100_ts_data *dd;
+ u8 *touch_data;
+ u8 device_id;
+ u8 prev_touches;
+ bool is_suspended;
+ bool int_pending;
+ struct mutex access_lock;
+ u32 pen_irq;
+};
+
+struct rm31100_ts *pts;
+/*
+static inline u16 join_bytes(u8 a, u8 b)
+{
+ u16 ab = 0;
+ ab = ab | a;
+ ab = ab << 8 | b;
+ return ab;
+}
+*/
+static s32 rm31100_ts_write_reg_u8(struct i2c_client *client, u8 reg, u8 val)
+{
+ s32 data;
+
+ data = i2c_smbus_write_byte_data(client, reg, val);
+ if (data < 0)
+ dev_err(&client->dev, "error %d in writing reg 0x%x\n",
+ data, reg);
+
+ return data;
+}
+
+static s32 rm31100_ts_read_reg_u8(struct i2c_client *client, u8 reg)
+{
+ s32 data;
+
+ data = i2c_smbus_read_byte_data(client, reg);
+ if (data < 0)
+ dev_err(&client->dev, "error %d in reading reg 0x%x\n",
+ data, reg);
+
+ return data;
+}
+
+static int rm31100_ts_read(struct i2c_client *client, u8 reg, u8 *buf, int num)
+{
+ struct i2c_msg xfer_msg[2];
+
+ xfer_msg[0].addr = client->addr;
+ xfer_msg[0].len = 1;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = ®
+
+ xfer_msg[1].addr = client->addr;
+ xfer_msg[1].len = num;
+ xfer_msg[1].flags = I2C_M_RD;
+ xfer_msg[1].buf = buf;
+
+ return i2c_transfer(client->adapter, xfer_msg, 2);
+}
+
+static int rm31100_ts_write_client_dma(struct i2c_client *client, u8 *buf, int num)
+{
+ struct i2c_msg xfer_msg[1];
+
+ xfer_msg[0].addr = I2C_DMA_CLIENT_ADDR;
+ xfer_msg[0].len = num;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = buf;
+
+ return i2c_transfer(client->adapter, xfer_msg, 1);
+}
+
+static int rm31100_ts_write(struct i2c_client *client, u8 *buf, int num)
+{
+ struct i2c_msg xfer_msg[1];
+
+ xfer_msg[0].addr = client->addr;
+ xfer_msg[0].len = num;
+ xfer_msg[0].flags = 0;
+ xfer_msg[0].buf = buf;
+
+ return i2c_transfer(client->adapter, xfer_msg, 1);
+}
+#ifdef CONFIG_MISC_DEV
+static int dev_open(struct inode *inode, struct file *filp)
+{
+ mutex_lock(&pts->access_lock);
+ return 0;
+}
+
+static int dev_release(struct inode *inode, struct file *filp)
+{
+ mutex_unlock(&pts->access_lock);
+ return 0;
+}
+static ssize_t
+dev_read(struct file *filp, char __user *buf, size_t count, loff_t *pos)
+{
+ u8 *kbuf;
+ struct i2c_msg xfer_msg;
+ /*static char out[] = "1234567890";*/
+ /*static int idx;*//*= 0; remove by checkpatch*/
+ int i;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (kbuf == NULL)
+ return -ENOMEM;
+
+ /*xfer_msg.addr = pts->client->addr;*/
+ xfer_msg.addr = I2C_CLIENT_ADDR;
+ xfer_msg.len = count;
+ xfer_msg.flags = I2C_M_RD;
+ xfer_msg.buf = kbuf;
+
+ i2c_transfer(pts->client->adapter, &xfer_msg, 1);
+
+ if (copy_to_user(buf, kbuf, count) == 0)
+ return count;
+ else
+ return -EFAULT;
+}
+
+static ssize_t
+dev_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos)
+{
+ u8 *kbuf;
+ ssize_t status = 0;
+ int i;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (kbuf == NULL) {
+ dev_err("kmalloc() fail\n");
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(kbuf, buf, count) == 0) {
+ pts->client->addr = I2C_CLIENT_ADDR;
+ if (rm31100_ts_write(pts->client, kbuf, count) < 0)
+ status = -EFAULT;
+ else
+ status = count;
+ } else {
+ dev_err("copy_from_user() fail\n");
+ status = -EFAULT;
+ }
+
+ kfree(kbuf);
+ return status;
+}
+
+static struct file_operations dev_fops = {
+ .owner = THIS_MODULE,
+ .open = dev_open,
+ .release = dev_release,
+ .read = dev_read,
+ .write = dev_write,
+ /*.unlocked_ioctl = dev_ioctl,*/
+};
+
+static struct miscdevice raydium_ts_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "raydium_ts",
+ .fops = &dev_fops,
+};
+#endif
+
+
+ssize_t show(struct device_driver *drv, char *buff)
+{
+ struct i2c_msg xfer_msg;
+ int num = 10;
+ char buf[100];
+ /*int i;*/
+
+ xfer_msg.addr = pts->client->addr;
+ xfer_msg.len = num;
+ xfer_msg.flags = I2C_M_RD;
+ xfer_msg.buf = buf;
+ pts->client->addr = I2C_CLIENT_ADDR;
+ i2c_transfer(pts->client->adapter, &xfer_msg, 1);
+
+ return 0;
+}
+
+ssize_t store(struct device_driver *drv, const char *buf, size_t count)
+{
+ /*unsigned char pkt[] = { 0xF2, 5, 1, 1 };*/
+ unsigned char pkt[] = { 0xF1, 5, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
+
+ pts->client->addr = I2C_CLIENT_ADDR;
+ rm31100_ts_write(pts->client, pkt, sizeof(pkt));
+
+ return sizeof(pkt);
+}
+
+DRIVER_ATTR(myAttr, 0x777, show, store);
+
+static void report_data(struct rm31100_ts *dev, u16 x, u16 y,
+ u8 pressure, u8 id)
+{
+ struct input_dev *input_dev = dev->input;
+ if (dev->pdata->swap_xy)
+ swap(x, y);
+
+ input_mt_slot(input_dev, id);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
+ input_report_abs(input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, dev->dd->finger_size);
+/*
+ dev_dbg("%s(): id =%2hhd, x =%4hd, y =%4hd, pressure = %hhd\n",
+ __func__, id, x, y, pressure);
+*/
+}
+
+static void process_rm31100_data(struct rm31100_ts *ts)
+{
+ u8 id, pressure, touches, i;
+ u16 x, y;
+
+ touches = ts->touch_data[ts->dd->touch_index];
+
+ if (touches > 0) {
+ for (i = 0; i < touches; i++) {
+ id = ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->id_index];
+ pressure = ts->touch_data[i * ts->dd->touch_bytes +
+ ts->dd->z_index];
+ x = get_unaligned_le16(&(ts->touch_data[i *
+ ts->dd->touch_bytes + ts->dd->x_index]));
+ y = get_unaligned_le16(&(ts->touch_data[i *
+ ts->dd->touch_bytes + ts->dd->y_index]));
+ report_data(ts, x, y, pressure, id);
+ }
+ } else
+ input_mt_sync(ts->input);
+
+ ts->prev_touches = touches;
+ /*input_report_key(ts->input, BTN_TOUCH, 1);*/
+ input_mt_report_pointer_emulation(ts->input, true);
+ input_sync(ts->input);
+}
+
+/*static void rm31100_ts_xy_worker(struct work_struct *work) JL remove*/
+static void rm31100_ts_xy_worker(struct rm31100_ts *work)
+{
+ int rc;
+ u8 client_dma_package[4] = {0x0f, 0x00, 0x20, 0x81};
+ struct rm31100_ts *ts = work;
+
+ if (ts->is_suspended == true) {
+ dev_dbg(&ts->client->dev, "TS is supended\n");
+ ts->int_pending = true;
+ return;
+ }
+
+ mutex_lock(&ts->access_lock);
+ /* read data from DATA_REG */
+ /*RM31100 DMA Mode*/
+ rc = rm31100_ts_write_client_dma(ts->client, client_dma_package, 0x04);
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "write client dma failed\n");
+ goto schedule;
+ }
+ rc = rm31100_ts_read(ts->client, ts->dd->data_reg, ts->touch_data,
+ ts->dd->data_size);
+
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "read failed\n");
+ goto schedule;
+ }
+
+ if (ts->touch_data[ts->dd->touch_index] == INVALID_DATA)
+ goto schedule;
+
+ /* write to STATUS_REG to release lock */
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0) {
+ dev_err(&ts->client->dev, "write failed, try once more\n");
+
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0)
+ dev_err(&ts->client->dev, "write failed, exiting\n");
+ }
+
+ process_rm31100_data(ts);
+schedule:
+ mutex_unlock(&ts->access_lock);
+}
+
+static irqreturn_t rm31100_ts_irq(int irq, void *dev_id)
+{
+ struct rm31100_ts *ts = dev_id;
+
+ rm31100_ts_xy_worker(ts);
+ return IRQ_HANDLED;
+}
+
+static int rm31100_ts_init_ts(struct i2c_client *client, struct rm31100_ts *ts)
+{
+ /*struct input_dev *input_device;*/
+ /*int rc = 0;*/
+
+ ts->dd = &devices[ts->device_id];
+
+ if (!ts->pdata->nfingers) {
+ dev_err(&client->dev, "Touches information not specified\n");
+ return -EINVAL;
+ }
+
+ if (ts->device_id == rm3110x) {
+ if (ts->pdata->nfingers > 2) {
+ dev_err(&client->dev, "Touches >=1 & <= 2\n");
+ return -EINVAL;
+ }
+ ts->dd->data_size = ts->dd->touch_bytes;
+ ts->dd->touch_index = 0x0;
+ } else if (ts->device_id == rm31100) {
+ if (ts->pdata->nfingers > 10) {
+ dev_err(&client->dev, "Touches >=1 & <= 10\n");
+ return -EINVAL;
+ }
+ ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
+ ts->dd->touch_meta_data;
+ ts->dd->touch_index = 0x0;
+ }
+ /* w001 */
+ else {
+ ts->dd->data_size = ts->pdata->nfingers * ts->dd->touch_bytes +
+ ts->dd->touch_meta_data;
+ ts->dd->touch_index = 0x0;
+ }
+
+ ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
+ if (!ts->touch_data) {
+ pr_err("%s: Unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int rm31100_ts_suspend(struct device *dev)
+{
+ struct rm31100_ts *ts = dev_get_drvdata(dev);
+ int rc = 0;
+
+ if (device_may_wakeup(dev)) {
+ /* mark suspend flag */
+ ts->is_suspended = true;
+ enable_irq_wake(ts->pen_irq);
+ }
+
+ disable_irq(ts->pen_irq);
+
+ gpio_free(ts->pdata->irq_gpio);
+
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(0);
+ if (rc) {
+ dev_err(dev, "unable to goto suspend\n");
+ return rc;
+ }
+ }
+ return 0;
+}
+
+static int rm31100_ts_resume(struct device *dev)
+{
+ struct rm31100_ts *ts = dev_get_drvdata(dev);
+
+ int rc = 0;
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(ts->pen_irq);
+
+ ts->is_suspended = false;
+
+ if (ts->int_pending == true)
+ ts->int_pending = false;
+ } else {
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(1);
+ if (rc) {
+ dev_err(dev, "unable to resume\n");
+ return rc;
+ }
+ }
+
+ enable_irq(ts->pen_irq);
+
+ /* Clear the status register of the TS controller */
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg, ts->dd->update_data);
+ if (rc < 0) {
+ dev_err(&ts->client->dev,
+ "write failed, try once more\n");
+
+ rc = rm31100_ts_write_reg_u8(ts->client,
+ ts->dd->status_reg,
+ ts->dd->update_data);
+ if (rc < 0)
+ dev_err(&ts->client->dev,
+ "write failed, exiting\n");
+ }
+ }
+
+ return 0;
+}
+
+static struct dev_pm_ops rm31100_ts_pm_ops = {
+ .suspend = rm31100_ts_suspend,
+ .resume = rm31100_ts_resume,
+};
+#endif
+
+static int rm_input_dev_create(struct rm31100_ts *ts)
+{
+ struct input_dev *input_device;
+ int rc = 0;
+ ts->prev_touches = 0;
+
+ input_device = input_allocate_device();
+ if (!input_device) {
+ rc = -ENOMEM;
+ goto error_alloc_dev;
+ }
+ ts->input = input_device;
+
+ input_device->name = "raydium_ts";
+ input_device->id.bustype = BUS_I2C;
+ input_device->dev.parent = &ts->client->dev;
+ input_set_drvdata(input_device, ts);
+
+ __set_bit(EV_ABS, input_device->evbit);
+ __set_bit(INPUT_PROP_DIRECT, input_device->propbit);
+ __set_bit(BTN_TOUCH, input_device->keybit);
+
+
+ if (ts->device_id == rm31100) {
+ /* set up virtual key */
+ __set_bit(EV_KEY, input_device->evbit);
+ }
+ input_mt_init_slots(input_device,
+ MAX_REPORT_TOUCHED_POINTS, 0);
+ input_set_abs_params(input_device, ABS_MT_POSITION_X,
+ ts->pdata->dis_min_x, ts->pdata->dis_max_x, 0, 0);
+ input_set_abs_params(input_device, ABS_MT_POSITION_Y,
+ ts->pdata->dis_min_y, ts->pdata->dis_max_y, 0, 0);
+ input_set_abs_params(input_device, ABS_MT_PRESSURE,
+ 0, 0xFF, 0, 0);
+ input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
+ 0, 0xFF, 0, 0);
+ rc = input_register_device(input_device);
+ if (rc)
+ goto error_unreg_device;
+
+ return 0;
+
+error_unreg_device:
+ input_free_device(input_device);
+error_alloc_dev:
+ ts->input = NULL;
+ return rc;
+}
+
+static int rm31100_initialize(struct i2c_client *client)
+{
+ struct rm31100_ts *ts = i2c_get_clientdata(client);
+ int rc = 0, /*retry_cnt = 0,*/ temp_reg;
+ /* power on the device */
+ if (ts->pdata->power_on) {
+ rc = ts->pdata->power_on(1);
+ if (rc) {
+ pr_err("%s: Unable to power on the device\n", __func__);
+ goto error_dev_setup;
+ }
+ }
+
+ /* read one byte to make sure i2c device exists */
+ if (ts->device_id == rm3110x)
+ temp_reg = 0x01;
+ else if (ts->device_id == rm31100)
+ temp_reg = 0x00;
+ else
+ temp_reg = 0x05;
+
+ rc = rm31100_ts_read_reg_u8(client, temp_reg);
+ if (rc < 0) {
+ dev_err(&client->dev, "i2c sanity check failed\n");
+ goto error_power_on;
+ }
+
+ rc = rm31100_ts_init_ts(client, ts);
+ if (rc < 0) {
+ dev_err(&client->dev, "rm31100_ts init failed\n");
+ goto error_mutex_destroy;
+ }
+
+ /* configure touchscreen reset out gpio */
+ rc = gpio_request(ts->pdata->resout_gpio, "rm31100_resout_gpio");
+ if (rc) {
+ pr_err("%s: unable to request gpio %d\n",
+ __func__, ts->pdata->resout_gpio);
+ goto error_uninit_ts;
+ }
+
+ rc = gpio_direction_output(ts->pdata->resout_gpio, 0);
+ if (rc) {
+ pr_err("%s: unable to set direction for gpio %d\n",
+ __func__, ts->pdata->resout_gpio);
+ goto error_resout_gpio_dir;
+ }
+ /* reset gpio stabilization time */
+ msleep(20);
+
+ return 0;
+error_resout_gpio_dir:
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+error_uninit_ts:
+ input_unregister_device(ts->input);
+ kfree(ts->touch_data);
+error_mutex_destroy:
+ mutex_destroy(&ts->access_lock);
+error_power_on:
+ if (ts->pdata->power_on)
+ ts->pdata->power_on(0);
+error_dev_setup:
+ if (ts->pdata->dev_setup)
+ ts->pdata->dev_setup(0);
+ return rc;
+}
+
+static void rm_initialize_async(void *data, async_cookie_t cookie)
+{
+ struct rm31100_ts *ts = data;
+ struct i2c_client *client = ts->client;
+ unsigned long irqflags;
+ int err = 0;
+
+ mutex_lock(&ts->access_lock);
+
+ err = rm31100_initialize(client);
+ if (err < 0) {
+ dev_err(&client->dev, "probe failed! unbind device.\n");
+ goto error_free_mem;
+ }
+
+ err = rm_input_dev_create(ts);
+ if (err) {
+ dev_err(&client->dev, "%s crated failed, %d\n", __func__, err);
+ goto error_goio_release;
+ }
+
+ irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING;
+
+ err = request_threaded_irq(ts->pen_irq, NULL,
+ rm31100_ts_irq,
+ irqflags | IRQF_ONESHOT,
+ ts->client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto error_dev_release;
+ }
+
+ mutex_unlock(&ts->access_lock);
+
+ return;
+
+error_dev_release:
+ input_free_device(ts->input);
+error_goio_release:
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+error_free_mem:
+ mutex_unlock(&ts->access_lock);
+ kfree(ts);
+ return;
+}
+
+
+/*static int __devinit rm31100_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)*/
+static int rm31100_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rm31100_ts *ts;
+ struct rm3110x_ts_platform_data *pdata = client->dev.platform_data;
+ int rc/*, temp_reg*/;
+ union i2c_smbus_data dummy;
+
+ if (!pdata) {
+ dev_err(&client->dev, "platform data is required!\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA)) {
+ dev_err(&client->dev, "I2C functionality not supported\n");
+ return -EIO;
+ }
+ /* Make sure there is something at this address */
+ if (i2c_smbus_xfer(client->adapter, client->addr, 0,
+ I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
+ return -ENODEV;
+
+ ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+ pts = ts;
+
+ /* Enable runtime PM ops, start in ACTIVE mode */
+ rc = pm_runtime_set_active(&client->dev);
+ if (rc < 0)
+ dev_warn(&client->dev, "unable to set runtime pm state\n");
+ pm_runtime_enable(&client->dev);
+
+ ts->client = client;
+ ts->pdata = pdata;
+ i2c_set_clientdata(client, ts);
+ ts->device_id = id->driver_data;
+
+ if (ts->pdata->dev_setup) {
+ rc = ts->pdata->dev_setup(1);
+ if (rc < 0) {
+ dev_err(&client->dev, "dev setup failed\n");
+ goto error_touch_data_alloc;
+ }
+ }
+
+
+ ts->is_suspended = false;
+ ts->int_pending = false;
+ /*mutex_init(&ts->sus_lock); JL remove*/
+ mutex_init(&ts->access_lock);
+
+ async_schedule(rm_initialize_async, ts);
+
+ device_init_wakeup(&client->dev, ts->pdata->wakeup);
+ return 0;
+
+error_touch_data_alloc:
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_disable(&client->dev);
+ kfree(ts);
+ return rc;
+}
+
+/*static int __devexit RM31100_ts_remove(struct i2c_client *client)*/
+static int rm31100_ts_remove(struct i2c_client *client)
+{
+ struct rm31100_ts *ts = i2c_get_clientdata(client);
+
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_disable(&client->dev);
+
+ device_init_wakeup(&client->dev, 0);
+ free_irq(ts->pen_irq, ts);
+
+ gpio_free(ts->pdata->irq_gpio);
+
+ if (ts->pdata->resout_gpio >= 0)
+ gpio_free(ts->pdata->resout_gpio);
+ input_unregister_device(ts->input);
+
+ /*mutex_destroy(&ts->sus_lock); JL remove*/
+ mutex_destroy(&ts->access_lock);
+
+ if (ts->pdata->power_on)
+ ts->pdata->power_on(0);
+
+ if (ts->pdata->dev_setup)
+ ts->pdata->dev_setup(0);
+
+ kfree(ts->touch_data);
+ kfree(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id rm31100_ts_id[] = {
+ {"RM31100", rm31100},
+ {"RM3110x", rm3110x},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rm31100_ts_id);
+
+
+static struct i2c_driver rm31100_ts_driver = {
+ .driver = {
+ .name = "raydium_ts",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &rm31100_ts_pm_ops,
+#endif
+ },
+ .probe = rm31100_ts_probe,
+ .remove = rm31100_ts_remove,
+ .id_table = rm31100_ts_id,
+};
+
+static int __init rm31100_ts_init(void)
+{
+ int rc;
+ int rc2;
+
+ rc = i2c_add_driver(&rm31100_ts_driver);
+
+ rc2 = driver_create_file(&rm31100_ts_driver.driver,
+ &driver_attr_myAttr);
+
+ return rc;
+}
+/* Making this as late init to avoid power fluctuations
+ * during LCD initialization.
+ */
+module_init(rm31100_ts_init);
+
+static void __exit rm31100_ts_exit(void)
+{
+ i2c_del_driver(&rm31100_ts_driver);
+}
+module_exit(rm31100_ts_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("rm31100-rm3110x touchscreen controller driver");
+MODULE_AUTHOR("Raydium");
+MODULE_ALIAS("platform:rm31100_ts");
--
2.1.2
^ permalink raw reply related
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