* [PATCH v14 09/12] input: cyapa: add gen5 trackpad device firmware update function support
From: Dudley Du @ 2014-12-12 2:27 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1418351262-8163-1-git-send-email-dudley.dulixin@gmail.com>
Add firmware image update function supported for gen5 trackpad device,
it can be used through sysfs update_fw interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/Kconfig | 1 +
drivers/input/mouse/cyapa_gen5.c | 290 +++++++++++++++++++++++++++++++++++++++
2 files changed, 291 insertions(+)
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index d8b46b0..728490e 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -206,6 +206,7 @@ config MOUSE_BCM5974
config MOUSE_CYAPA
tristate "Cypress APA I2C Trackpad support"
depends on I2C
+ select CRC_ITU_T
help
This driver adds support for Cypress All Points Addressable (APA)
I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index c2340ae..e4bb6e4 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -18,6 +18,7 @@
#include <linux/completion.h>
#include <linux/slab.h>
#include <linux/unaligned/access_ok.h>
+#include <linux/crc-itu-t.h>
#include "cyapa.h"
@@ -911,6 +912,86 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
return -EAGAIN;
}
+static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ u16 length = 0;
+ u16 data_len = 0;
+ u16 meta_data_crc = 0;
+ u16 cmd_crc = 0;
+ u8 bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + 3];
+ int bl_gen5_activate_size = 0;
+ u8 resp_data[11];
+ int resp_len;
+ struct cyapa_tsg_bin_image *image;
+ int records_num;
+ u8 *data;
+ int error;
+
+ /* Try to dump all buffered report data before send any command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ bl_gen5_activate_size = sizeof(bl_gen5_activate);
+ memset(bl_gen5_activate, 0, bl_gen5_activate_size);
+
+ /* Output Report Register Address[15:0] = 0004h */
+ bl_gen5_activate[0] = 0x04;
+ bl_gen5_activate[1] = 0x00;
+
+ /* Total command length[15:0] */
+ length = bl_gen5_activate_size - 2;
+ put_unaligned_le16(length, &bl_gen5_activate[2]);
+ bl_gen5_activate[4] = 0x40; /* Report ID = 40h */
+ bl_gen5_activate[5] = 0x00; /* RSVD = 00h */
+
+ bl_gen5_activate[6] = GEN5_SOP_KEY; /* SOP = 01h */
+ bl_gen5_activate[7] = 0x48; /* Command Code = 48h */
+
+ /* 8 Key bytes and block size */
+ data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
+ /* Data Length[15:0] */
+ put_unaligned_le16(data_len, &bl_gen5_activate[8]);
+ bl_gen5_activate[10] = 0xa5; /* Key Byte 0 */
+ bl_gen5_activate[11] = 0x01;
+ bl_gen5_activate[12] = 0x02; /* . */
+ bl_gen5_activate[13] = 0x03; /* . */
+ bl_gen5_activate[14] = 0xff; /* . */
+ bl_gen5_activate[15] = 0xfe;
+ bl_gen5_activate[16] = 0xfd;
+ bl_gen5_activate[17] = 0x5a; /* Key Byte 7 */
+
+ /* Copy 60 bytes Meta Data Row Parameters */
+ image = (struct cyapa_tsg_bin_image *)fw->data;
+ records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /* APP_INTEGRITY row is always the last row block */
+ data = image->records[records_num - 1].record_data;
+ memcpy(&bl_gen5_activate[18], data, CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+
+ meta_data_crc = crc_itu_t(0xffff, &bl_gen5_activate[18],
+ CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+ /* Meta Data CRC[15:0] */
+ put_unaligned_le16(meta_data_crc,
+ &bl_gen5_activate[18 + CYAPA_TSG_FLASH_MAP_METADATA_SIZE]);
+
+ cmd_crc = crc_itu_t(0xffff, &bl_gen5_activate[6], 4 + data_len);
+ put_unaligned_le16(cmd_crc,
+ &bl_gen5_activate[bl_gen5_activate_size - 3]); /* CRC[15:0] */
+ bl_gen5_activate[bl_gen5_activate_size - 1] = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ bl_gen5_activate, sizeof(bl_gen5_activate),
+ resp_data, &resp_len, 12000,
+ cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
{
if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
@@ -960,6 +1041,210 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
return -ENODEV;
}
+static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
+{
+ int error;
+ u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
+ u8 resp_data[2];
+ int resp_len;
+
+ error = cyapa_poll_state(cyapa, 500);
+ if (error < 0)
+ return error;
+ if (cyapa->gen != CYAPA_GEN5)
+ return -EINVAL;
+
+ /* Already in Gen5 BL. Skipping exit. */
+ if (cyapa->state == CYAPA_STATE_GEN5_BL)
+ return 0;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EAGAIN;
+
+ /* Try to dump all buffered report data before send any command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ /*
+ * Send bootloader enter command to trackpad device,
+ * after enter bootloader, the response data is two bytes of 0x00 0x00.
+ */
+ resp_len = sizeof(resp_data);
+ memset(resp_data, 0, resp_len);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_application_launch_data,
+ true);
+ if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
+ return error < 0 ? error : -EAGAIN;
+
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ return 0;
+}
+
+static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
+{
+ int i;
+ struct cyapa_tsg_bin_image *image;
+ int flash_records_count;
+ u16 expected_app_crc;
+ u16 expected_app_integrity_crc;
+ u16 app_crc = 0;
+ u16 app_integrity_crc = 0;
+ u16 row_num;
+ u8 *data;
+ u32 app_start;
+ u16 app_len;
+ u32 img_start;
+ u16 img_len;
+ int record_index;
+ struct device *dev = &cyapa->client->dev;
+
+ image = (struct cyapa_tsg_bin_image *)fw->data;
+ flash_records_count = (fw->size -
+ sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+
+ /* APP_INTEGRITY row is always the last row block,
+ * and the row id must be 0x01ff */
+ row_num = get_unaligned_be16(
+ &image->records[flash_records_count - 1].row_number);
+ if (&image->records[flash_records_count - 1].flash_array_id != 0x00 &&
+ row_num != 0x01ff) {
+ dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
+ return -EINVAL;
+ }
+ data = image->records[flash_records_count - 1].record_data;
+ app_start = get_unaligned_le32(&data[4]);
+ app_len = get_unaligned_le16(&data[8]);
+ expected_app_crc = get_unaligned_le16(&data[10]);
+ img_start = get_unaligned_le32(&data[16]);
+ img_len = get_unaligned_le16(&data[20]);
+ expected_app_integrity_crc = get_unaligned_le16(&data[60]);
+
+ if ((app_start + app_len + img_start + img_len) %
+ CYAPA_TSG_FW_ROW_SIZE) {
+ dev_err(dev, "%s: invalid image alignment.\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Verify app_integrity crc */
+ app_integrity_crc = crc_itu_t(0xffff, data,
+ CYAPA_TSG_APP_INTEGRITY_SIZE);
+ if (app_integrity_crc != expected_app_integrity_crc) {
+ dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Verify application image CRC
+ */
+ record_index = app_start / CYAPA_TSG_FW_ROW_SIZE -
+ CYAPA_TSG_IMG_START_ROW_NUM;
+ data = (u8 *)&image->records[record_index].record_data;
+ app_crc = crc_itu_t(0xffff, data, CYAPA_TSG_FW_ROW_SIZE);
+ for (i = 1; i < (app_len / CYAPA_TSG_FW_ROW_SIZE); i++) {
+ data = (u8 *)&image->records[++record_index].record_data;
+ app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
+ }
+
+ if (app_crc != expected_app_crc) {
+ dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
+ struct cyapa_tsg_bin_image_data_record *flash_record)
+{
+ u8 flash_array_id;
+ u16 flash_row_id;
+ u16 record_len;
+ u8 *record_data;
+ u8 cmd[144]; /* 13 + 128+ 3 */
+ u16 cmd_len;
+ u16 data_len;
+ u16 crc;
+ u8 resp_data[11];
+ int resp_len;
+ int error;
+
+ flash_array_id = flash_record->flash_array_id;
+ flash_row_id = get_unaligned_be16(&flash_record->row_number);
+ record_len = get_unaligned_be16(&flash_record->record_len);
+ record_data = flash_record->record_data;
+
+ cmd_len = sizeof(cmd) - 2; /* Not include 2 bytes regisetr address. */
+ memset(cmd, 0, cmd_len + 2);
+ cmd[0] = 0x04; /* Register address */
+ cmd[1] = 0x00;
+
+ put_unaligned_le16(cmd_len, &cmd[2]);
+ cmd[4] = 0x40; /* Report id 40h */
+ cmd[5] = 0x00;
+
+ cmd[6] = GEN5_SOP_KEY; /* SOP = 01h */
+ cmd[7] = 0x39; /* Command code = 39h */
+ /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
+ data_len = 3 + record_len;
+ put_unaligned_le16(data_len, &cmd[8]);
+ cmd[10] = flash_array_id; /* Flash Array ID = 00h */
+ put_unaligned_le16(flash_row_id, &cmd[11]);
+
+ memcpy(&cmd[13], record_data, record_len);
+ crc = crc_itu_t(0xffff, &cmd[6], 4 + data_len);
+ put_unaligned_le16(crc, &cmd[2 + cmd_len - 3]);
+ cmd[2 + cmd_len - 1] = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct cyapa_tsg_bin_image *image =
+ (struct cyapa_tsg_bin_image *)fw->data;
+ struct cyapa_tsg_bin_image_data_record *flash_record;
+ int flash_records_count;
+ int i;
+ int error;
+
+ /* Try to dump all buffered data if exists before send commands. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ flash_records_count =
+ (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /*
+ * The last flash row 0x01ff has been written through bl_initiate
+ * command, so DO NOT write flash 0x01ff to trackpad device.
+ */
+ for (i = 0; i < (flash_records_count - 1); i++) {
+ flash_record = &image->records[i];
+ error = cyapa_gen5_write_fw_block(cyapa, flash_record);
+ if (error) {
+ dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
+ __func__, error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
{
u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
@@ -1648,6 +1933,11 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
}
const struct cyapa_dev_ops cyapa_gen5_ops = {
+ .check_fw = cyapa_gen5_check_fw,
+ .bl_enter = cyapa_gen5_bl_enter,
+ .bl_initiate = cyapa_gen5_bl_initiate,
+ .update_fw = cyapa_gen5_do_fw_update,
+
.initialize = cyapa_gen5_initialize,
.state_parse = cyapa_gen5_state_parse,
--
1.9.1
^ permalink raw reply related
* [PATCH v14 10/12] input: cyapa: add gen5 trackpad device read baseline function support
From: Dudley Du @ 2014-12-12 2:27 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1418351262-8163-1-git-send-email-dudley.dulixin@gmail.com>
Add read baseline function supported for gen5 trackpad device,
it can be used through sysfs baseline interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.h | 2 +
drivers/input/mouse/cyapa_gen5.c | 621 +++++++++++++++++++++++++++++++++++++++
2 files changed, 623 insertions(+)
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
index eafeb79..39e7941 100644
--- a/drivers/input/mouse/cyapa.h
+++ b/drivers/input/mouse/cyapa.h
@@ -285,6 +285,8 @@ struct cyapa {
u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */
int electrodes_x; /* Number of electrodes on the X Axis*/
int electrodes_y; /* Number of electrodes on the Y Axis*/
+ int electrodes_rx; /* Number of Rx electrodes */
+ int algined_electrodes_rx; /* 4 aligned */
int max_z;
/*
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index e4bb6e4..365a5b9 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -1533,6 +1533,625 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
return 0;
}
+static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
+ return -EINVAL;
+
+ /* Try to dump all buffered data when resuming scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[7] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
+ return -EINVAL;
+
+ /* Try to dump all buffered data when suspending scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static s32 two_complement_to_s32(s32 value, int num_bits)
+{
+ if (value >> (num_bits - 1))
+ value |= -1 << num_bits;
+ return value;
+}
+
+static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
+{
+ int data_size;
+ bool big_endian;
+ bool unsigned_type;
+ s32 value;
+
+ data_size = (data_format & 0x07);
+ big_endian = ((data_format & 0x10) == 0x00);
+ unsigned_type = ((data_format & 0x20) == 0x00);
+
+ if (buf_len < data_size)
+ return 0;
+
+ switch (data_size) {
+ case 1:
+ value = buf[0];
+ break;
+ case 2:
+ if (big_endian)
+ value = get_unaligned_be16(buf);
+ else
+ value = get_unaligned_le16(buf);
+ break;
+ case 4:
+ if (big_endian)
+ value = get_unaligned_be32(buf);
+ else
+ value = get_unaligned_le32(buf);
+ break;
+ default:
+ /* Should not happen, just as default case here. */
+ value = 0;
+ break;
+ }
+
+ if (!unsigned_type)
+ value = two_complement_to_s32(value, data_size * 8);
+
+ return value;
+}
+
+
+/*
+ * Read all the global mutual or self idac data or mutual or self local PWC
+ * data based on the @idac_data_type.
+ * If the input value of @data_size is 0, then means read global mutual or
+ * self idac data. For read global mutual idac data, @idac_max, @idac_min and
+ * @idac_ave are in order used to return the max value of global mutual idac
+ * data, the min value of global mutual idac and the average value of the
+ * global mutual idac data. For read global self idac data, @idac_max is used
+ * to return the global self cap idac data in Rx direction, @idac_min is used
+ * to return the global self cap idac data in Tx direction. @idac_ave is not
+ * used.
+ * If the input value of @data_size is not 0, than means read the mutual or
+ * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
+ * return the max, min and average value of the mutual or self local PWC data.
+ * Note, in order to raed mutual local PWC data, must read invoke this function
+ * to read the mutual global idac data firstly to set the correct Rx number
+ * value, otherwise, the read mutual idac and PWC data may not correct.
+ */
+static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 idac_data_type, int *data_size,
+ int *idac_max, int *idac_min, int *idac_ave)
+{
+ int i;
+ u8 cmd[12];
+ u8 resp_data[256];
+ int resp_len;
+ int read_len;
+ int value;
+ u16 offset;
+ int read_elements;
+ bool read_global_idac;
+ int sum, count, max_element_cnt;
+ int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
+ int electrodes_rx, electrodes_tx;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
+ (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
+ !data_size || !idac_max || !idac_min || !idac_ave)
+ return -EINVAL;
+
+ *idac_max = INT_MIN;
+ *idac_min = INT_MAX;
+ sum = count = tmp_count = 0;
+ electrodes_rx = electrodes_tx = 0;
+ if (*data_size == 0) {
+ /*
+ * Read global idac values firstly.
+ * Currently, no idac data exceed 4 bytes.
+ */
+ read_global_idac = true;
+ offset = 0;
+ *data_size = 4;
+ tmp_max = INT_MIN;
+ tmp_min = INT_MAX;
+ tmp_ave = tmp_sum = tmp_count = 0;
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (cyapa->algined_electrodes_rx == 0) {
+ if (cyapa->electrodes_rx != 0) {
+ electrodes_rx = cyapa->electrodes_rx;
+ electrodes_tx = (cyapa->electrodes_x ==
+ electrodes_rx) ?
+ cyapa->electrodes_y :
+ cyapa->electrodes_x;
+ } else {
+ electrodes_tx = min(cyapa->electrodes_x,
+ cyapa->electrodes_y);
+ electrodes_rx = max(cyapa->electrodes_x,
+ cyapa->electrodes_y);
+ }
+ cyapa->algined_electrodes_rx =
+ (electrodes_rx + 3) & ~3u;
+ }
+ max_element_cnt =
+ (cyapa->algined_electrodes_rx + 7) & ~7u;
+ } else {
+ max_element_cnt = 2;
+ }
+ } else {
+ read_global_idac = false;
+ if (*data_size > 4)
+ *data_size = 4;
+ /* Calculate the start offset in bytes of local PWC data. */
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ offset = cyapa->algined_electrodes_rx * (*data_size);
+ electrodes_tx =
+ (cyapa->electrodes_rx == cyapa->electrodes_x) ?
+ cyapa->electrodes_y : cyapa->electrodes_x;
+ max_element_cnt = ((cyapa->algined_electrodes_rx + 7) &
+ ~7u) * electrodes_tx;
+ } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ offset = 2;
+ max_element_cnt = cyapa->electrodes_x +
+ cyapa->electrodes_y;
+ max_element_cnt = (max_element_cnt + 3) & ~3u;
+ }
+ }
+
+ do {
+ read_elements = (256 - 10) / (*data_size);
+ read_elements = min(read_elements, max_element_cnt - count);
+ read_len = read_elements * (*data_size);
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x0a;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = cmd_code;
+ put_unaligned_le16(offset, &cmd[7]); /* Read Offset[15:0] */
+ put_unaligned_le16(read_len, &cmd[9]); /* Read Length[15:0] */
+ cmd[11] = idac_data_type;
+ resp_len = 10 + read_len;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 12,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data,
+ true);
+ if (error || resp_len < 10 ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != idac_data_type)
+ return (error < 0) ? error : -EAGAIN;
+ read_len = get_unaligned_le16(&resp_data[7]);
+ if (read_len == 0)
+ break;
+
+ *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ if (read_len < *data_size)
+ return -EINVAL;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ /* Rx's self global idac data. */
+ *idac_max = cyapa_parse_structure_data(
+ resp_data[9], &resp_data[10],
+ *data_size);
+ /* Tx's self global idac data. */
+ *idac_min = cyapa_parse_structure_data(
+ resp_data[9],
+ &resp_data[10 + *data_size],
+ *data_size);
+ break;
+ }
+
+ /* Read mutual global idac or local mutual/self PWC data. */
+ offset += read_len;
+ for (i = 10; i < (read_len + 10); i += *data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], *data_size);
+ *idac_min = min(value, *idac_min);
+ *idac_max = max(value, *idac_max);
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ tmp_count < cyapa->algined_electrodes_rx &&
+ read_global_idac) {
+ /*
+ * The value gap betwen global and local mutual
+ * idac data must bigger than 50%.
+ * Normally, global value bigger than 50,
+ * local values less than 10.
+ */
+ if (!tmp_ave || value > tmp_ave / 2) {
+ tmp_min = min(value, tmp_min);
+ tmp_max = max(value, tmp_max);
+ tmp_sum += value;
+ tmp_count++;
+
+ tmp_ave = tmp_sum / tmp_count;
+ }
+ }
+
+ sum += value;
+ count++;
+
+ if (count >= max_element_cnt)
+ goto out;
+ }
+ } while (true);
+
+out:
+ *idac_ave = count ? (sum / count) : 0;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (tmp_count == 0)
+ return 0;
+
+ if (tmp_count == cyapa->algined_electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ } else if (tmp_count == electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ cyapa->algined_electrodes_rx = electrodes_rx;
+ } else {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_tx;
+ cyapa->algined_electrodes_rx = tmp_count;
+ }
+
+ *idac_min = tmp_min;
+ *idac_max = tmp_max;
+ *idac_ave = tmp_ave;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
+ int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
+ int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
+{
+ int error;
+ int data_size;
+
+ *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
+ *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
+ if (error)
+ return error;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
+ return error;
+}
+
+static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
+ int *gidac_self_rx, int *gidac_self_tx,
+ int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
+{
+ int error;
+ int data_size;
+
+ *gidac_self_rx = *gidac_self_tx = 0;
+ *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ if (error)
+ return error;
+ *gidac_self_rx = *lidac_self_max;
+ *gidac_self_tx = *lidac_self_min;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ return error;
+}
+
+static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
+{
+ int error;
+ u8 cmd[7];
+ u8 resp_data[6];
+ int resp_len;
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x05;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = GEN5_CMD_EXECUTE_PANEL_SCAN; /* Command code */
+ resp_len = 6;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 7,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len != 6 ||
+ !VALID_CMD_RESP_HEADER(resp_data,
+ GEN5_CMD_EXECUTE_PANEL_SCAN) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
+ int *raw_data_max, int *raw_data_min, int *raw_data_ave,
+ u8 *buffer)
+{
+ int i;
+ u8 cmd[12];
+ u8 resp_data[256]; /* Max bytes can transfer one time. */
+ int resp_len;
+ int read_elements;
+ int read_len;
+ u16 offset;
+ s32 value;
+ int sum, count;
+ int data_size;
+ s32 *intp;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
+ (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
+ !raw_data_max || !raw_data_min || !raw_data_ave)
+ return -EINVAL;
+
+ intp = (s32 *)buffer;
+ *raw_data_max = INT_MIN;
+ *raw_data_min = INT_MAX;
+ sum = count = 0;
+ offset = 0;
+ read_elements = (256 - 10) / 4; /* Currently, max element size is 4. */
+ read_len = read_elements * 4;
+ do {
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x0a;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = cmd_code; /* Command code */
+ put_unaligned_le16(offset, &cmd[7]);
+ put_unaligned_le16(read_elements, &cmd[9]);
+ cmd[11] = raw_data_type;
+ resp_len = 10 + read_len;
+
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, 12,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len < 10 ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != raw_data_type)
+ return error ? error : -EAGAIN;
+
+ read_elements = get_unaligned_le16(&resp_data[7]);
+ if (read_elements == 0)
+ break;
+
+ data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ offset += read_elements;
+ if (read_elements) {
+ for (i = 10;
+ i < (read_elements * data_size + 10);
+ i += data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], data_size);
+ *raw_data_min = min(value, *raw_data_min);
+ *raw_data_max = max(value, *raw_data_max);
+
+ if (intp)
+ put_unaligned_le32(value, &intp[count]);
+
+ sum += value;
+ count++;
+
+ }
+ }
+
+ if (count >= raw_data_max_num)
+ break;
+
+ read_elements = (sizeof(resp_data) - 10) / data_size;
+ read_len = read_elements * data_size;
+ } while (true);
+
+ *raw_data_ave = count ? (sum / count) : 0;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
+ int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
+ int gidac_self_rx, gidac_self_tx;
+ int lidac_self_max, lidac_self_min, lidac_self_ave;
+ int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
+ int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
+ int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
+ int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
+ int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
+ int self_baseline_max, self_baseline_min, self_baseline_ave;
+ int error, resume_error;
+ int size;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EBUSY;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Read global and local mutual IDAC data. */
+ gidac_self_rx = gidac_self_tx = 0;
+ error = cyapa_gen5_read_mutual_idac_data(cyapa,
+ &gidac_mutual_max, &gidac_mutual_min,
+ &gidac_mutual_ave, &lidac_mutual_max,
+ &lidac_mutual_min, &lidac_mutual_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 3. Read global and local self IDAC data. */
+ error = cyapa_gen5_read_self_idac_data(cyapa,
+ &gidac_self_rx, &gidac_self_tx,
+ &lidac_self_max, &lidac_self_min,
+ &lidac_self_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 4. Execuate panel scan. It must be executed before read data. */
+ error = cyapa_gen5_execute_panel_scan(cyapa);
+ if (error)
+ goto resume_scanning;
+
+ /* 5. Retrieve panel scan, mutual cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &raw_cap_mutual_max, &raw_cap_mutual_min,
+ &raw_cap_mutual_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 6. Retrieve panel scan, self cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_RAW_DATA,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &raw_cap_self_max, &raw_cap_self_min,
+ &raw_cap_self_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_diffdata_max, &mutual_diffdata_min,
+ &mutual_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 8. Retrieve panel scan, self cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_diffdata_max, &self_diffdata_min,
+ &self_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 9. Retrieve panel scan, mutual cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_BASELINE,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_baseline_max, &mutual_baseline_min,
+ &mutual_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 10. Retrieve panel scan, self cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_BASELINE,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_baseline_max, &self_baseline_min,
+ &self_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 11. Resume Scanning*/
+ resume_error = cyapa_gen5_resume_scanning(cyapa);
+ if (resume_error || error)
+ return resume_error ? resume_error : error;
+
+ /* 12. Output data strings */
+ size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
+ gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
+ lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
+ gidac_self_rx, gidac_self_tx,
+ lidac_self_min, lidac_self_max, lidac_self_ave);
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
+ raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
+ mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
+ self_diffdata_min, self_diffdata_max, self_diffdata_ave,
+ mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
+ self_baseline_min, self_baseline_max, self_baseline_ave);
+ return size;
+}
+
static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
u8 *buf, int len)
{
@@ -1938,6 +2557,8 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.bl_initiate = cyapa_gen5_bl_initiate,
.update_fw = cyapa_gen5_do_fw_update,
+ .show_baseline = cyapa_gen5_show_baseline,
+
.initialize = cyapa_gen5_initialize,
.state_parse = cyapa_gen5_state_parse,
--
1.9.1
^ permalink raw reply related
* [PATCH v14 11/12] input: cyapa: add gen5 trackpad device force re-calibrate function support
From: Dudley Du @ 2014-12-12 2:27 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1418351262-8163-1-git-send-email-dudley.dulixin@gmail.com>
Add force re-calibrate function supported for gen5 trackpad device,
it can be used through sysfs calibrate interface.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa_gen5.c | 65 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 365a5b9..f673bb3 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -1581,6 +1581,70 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
return 0;
}
+static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa,
+ u8 calibrate_sensing_mode_type)
+{
+ u8 cmd[8];
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ cmd[0] = 0x04;
+ cmd[1] = 0x00;
+ cmd[2] = 0x06;
+ cmd[3] = 0x00;
+ cmd[4] = GEN5_APP_CMD_REPORT_ID;
+ cmd[5] = 0x00;
+ cmd[6] = GEN5_CMD_CALIBRATE;
+ cmd[7] = calibrate_sensing_mode_type;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_do_calibrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error, calibrate_error;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Do mutual capacitance fine calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_MUTUAL_CAP_FINE);
+ if (calibrate_error)
+ goto resume_scanning;
+
+ /* 3. Do self capacitance calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_SELF_CAP);
+ if (calibrate_error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 4. Resume Scanning*/
+ error = cyapa_gen5_resume_scanning(cyapa);
+ if (error || calibrate_error)
+ return error ? error : calibrate_error;
+
+ return count;
+}
+
static s32 two_complement_to_s32(s32 value, int num_bits)
{
if (value >> (num_bits - 1))
@@ -2558,6 +2622,7 @@ const struct cyapa_dev_ops cyapa_gen5_ops = {
.update_fw = cyapa_gen5_do_fw_update,
.show_baseline = cyapa_gen5_show_baseline,
+ .calibrate_store = cyapa_gen5_do_calibrate,
.initialize = cyapa_gen5_initialize,
--
1.9.1
^ permalink raw reply related
* [PATCH v14 12/12] input: cyapa: add acpi device id supported
From: Dudley Du @ 2014-12-12 2:27 UTC (permalink / raw)
To: dmitry.torokhov, rydberg; +Cc: Dudley Du, bleung, linux-input, linux-kernel
In-Reply-To: <1418351262-8163-1-git-send-email-dudley.dulixin@gmail.com>
Add acpi device tree supported.
acpi device id "CYAP0000" is for old gen3 trackpad devices.
acpi device id "CYAP0001" is for new gen5 trackpad devices.
TEST=test on Chromebooks.
Signed-off-by: Dudley Du <dudley.dulixin@gmail.com>
---
drivers/input/mouse/cyapa.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index ff8cd9b..c992bd6 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
#include "cyapa.h"
@@ -1322,11 +1323,23 @@ static const struct i2c_device_id cyapa_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cyapa_acpi_id[] = {
+ { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */
+ { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
+#endif
+
static struct i2c_driver cyapa_driver = {
.driver = {
.name = "cyapa",
.owner = THIS_MODULE,
.pm = &cyapa_pm_ops,
+#ifdef CONFIG_ACPI
+ .acpi_match_table = ACPI_PTR(cyapa_acpi_id),
+#endif
},
.probe = cyapa_probe,
--
1.9.1
^ permalink raw reply related
* [PATCH v14 00/12] input: cyapa: instruction of cyapa patches
From: Dudley Du @ 2014-12-12 2:27 UTC (permalink / raw)
To: dmitry.torokhov, rydberg
Cc: Dudley Du, bleung, dso, linux-input, linux-kernel
V14 patches have below updates, details of other updates see history list:
1) Correct 9 miss spelling issues of "bufferred" to "buffered".
2) Fix the upgrade issue of removing MOUSE_CYAPA config when make oldconfig
by replase "depends on I2C && CRC_ITU_T" with
"depends on I2C"
"select CRC_ITU_T"
in patch 9.
This patch series is aimed to re-design the cyapa driver to support
old gen3 trackpad devices and new gen5 trackpad devices in one
cyapa driver, it's for easily productions support based on
customers' requirements. And add sysfs functions and interfaces
supported that required by users and customers.
Since the earlier gen3 and the latest gen5 trackpad devices using
two different chipsets, and have different protocols and interfaces,
so if supported these two type trackpad devices in two different drivers,
then it will be difficult to manage productions and later firmware updates.
e.g.: It will cause customer don't know which one trackpad device firmware
image to use and update when it has been used and integrated
in same one productions, so here we support these two trackpad
devices in same on driver.
The new design cyapa driver contains:
cyapa.c - the core of the re-design, supply interfaces and
functions to system and read trackpad devices.
cyapa.h - header file including macros and data structure definitions.
cyapa_gen3.c - functions support for gen3 trackpad devices,
cyapa_gen5.c - functions support for gen5 trackpad devices.
Beside this introduction patch, it has 12 patches listed as below.
For these patches, each one is patched based on previous one.
patch 1/12: re-design cyapa driver with core functions and interface
to support multi-type trackpad devices.
patch 2/12: add gen5 trackpad device basic functions supported into the
re-design cyapa driver.
patch 3/12: add power management interfaces supported for the device.
patch 4/12: add runtime power management interfaces supported for the device.
patch 5/12: add sysfs interfaces supported in the cyapa driver.
Including read firmware version, get production ID, read baseline,
re-calibrate trackpad baselines and do trackpad firmware update.
patch 6/12: add gen3 trackpad device's firmware update function supported.
patch 7/12: add gen3 trackpad device's read baseline function supported.
patch 8/12: add gen3 trackpad device's force re-calibrate function supported.
patch 9/12: add gen5 trackpad device's firmware update function supported.
patch 10/12: add gen5 trackpad device's read baseline function supported.
patch 11/12: add gen5 trackpad device's force re-calibrate function.
patch 12/12: add acpi device id supported.
History patch series modifications list:
V13 patches have below updates, details of other updates see history list:
1) Remove all debugfs interface, including read_fw and raw_data interfaces.
2) This patches are made based linux next-20141208.
V12 patches have below main updates compared with v11 patches:
1) Add check that when TP is detected but not operational, do not exit driver
immediately, but wait and export the update_fw interface for recovering.
2) Re-arrange the function codes, remove unnesseary protype definitions in
the header file.
V11 patches have below main updates compared with v10 patches:
1) Add add acpi device id supported for old gen3 and new gen5 trackpad devices.
2) Fix the unable to update firmware issue when cyapa_open is not called
which means the irq for firwmare update process is not enabled. This fix
by checking if the irq is enabled, if not then enable irq before start to
do firmware update.
V10 patches have below main updates compared with v9 patches:
1) Modify code to following kernel code style.
e.g.: correct to use error as return name when there is only error path,
and fix the checkpatch.sh wanting in the driver.
2) Remove cyapa_remove method and use input open and close interface to
following device resouse management infrastructure.
3) Modify cyapa_detect method to return tristate issue to make the return value
much more consistent and clear.
4) Use platform supplied functions as possible instead of driver
specific rewritten version.
V9 patches have below updates compared with v8 patches:
1) Removed all async thread stuff from the driver.
2) Split driver into 18 patches for each function change one patch.
V8 patches have below updates compared with v7 patches:
1) [PATCH v8 01/13] - Remove the async thread for device detect in
probe routine, now the device detect process is completely done within
the device probe routine.
2) [PATCH v8 01/13] - Split the irq cmd hander function to separated
function cyapa_default_irq_cmd_handler() and set it to interface
cyapa_default_ops.irq_cmd_handler.
3) [PATCH v8 06/13] - Add cyapa->gen check in cyapa_gen3_irq_cmd_handler()
to avoid miss-enter when device protocol is still in detecting.
V7 patches have below updates compared with v6 patches:
1) [PATCH v7 01/13] - Split the irq cmd hander function to separated
function cyapa_default_irq_cmd_handler() and set it to interface
cyapa_default_ops.irq_cmd_handler.
2) [PATCH v7 06/13] - Add cyapa->gen check in cyapa_gen3_irq_cmd_handler()
to avoid miss-enter when device protocol is still in detecting.
V6 patches have below updates compared with v5 patches:
1) Remove patch 14 of the lid filtering from the cyapa driver.
V5 patches have below updates compared with v4 patches:
1) Uses get_device()/put_device() instead of kobject_get()/kobject_put();
2) Fix memories freed before debugfs entries issue;
3) Make cyapa_debugs_root valid in driver module level
in module_init()/moudle_exit() ;
4) Fix i2c_transfer() may return partial transfer issues.
5) Add cyapa->removed flag to avoid detecting thread may still running
when driver module is removed.
6) Fix the meanings of some comments and return error code not clear issue.
^ permalink raw reply
* Re: NULL pointer dereference in i2c-hid
From: Gabriele Mazzotta @ 2014-12-12 8:12 UTC (permalink / raw)
To: Andrew Duggan
Cc: Mika Westerberg, linux-input, linux-kernel, benjamin.tissoires,
jkosina
In-Reply-To: <548A3618.1020903@synaptics.com>
On Thursday 11 December 2014 16:26:00 Andrew Duggan wrote:
> On 12/11/2014 01:57 PM, Gabriele Mazzotta wrote:
> > On Thursday 11 December 2014 13:34:02 Andrew Duggan wrote:
> >> On 12/11/2014 01:17 PM, Gabriele Mazzotta wrote:
> >>> On Thursday 11 December 2014 12:46:53 Andrew Duggan wrote:
> >>>> On 12/11/2014 11:40 AM, Gabriele Mazzotta wrote:
> >>>>> On Thursday 11 December 2014 11:21:43 Andrew Duggan wrote:
> >>>>>> On 12/11/2014 11:11 AM, Gabriele Mazzotta wrote:
> >>>>>>> On Thursday 11 December 2014 10:40:05 Andrew Duggan wrote:
> >>>>>>>> On 12/11/2014 10:16 AM, Gabriele Mazzotta wrote:
> >>>>>>>>> On Thursday 11 December 2014 16:03:07 Mika Westerberg wrote:
> >>>>>>>>>> On Thu, Dec 11, 2014 at 10:58:01AM +0200, Mika Westerberg wrote:
> >>>>>>>>>>> On Wed, Dec 10, 2014 at 06:04:51PM +0100, Gabriele Mazzotta wrote:
> >>>>>>>>>>>> my laptop uses a touchpad that needs hid-rmi along with i2c-hid to work.
> >>>>>>>>>>>> i2c-hid and hid-rmi can be loaded and unloaded independelty from each
> >>>>>>>>>>>> other, however since 34f439e4afcd ("HID: i2c-hid: add runtime PM support")
> >>>>>>>>>>>> if I unload hid-rmi and after it I also unload i2c-hid, I get a NULL
> >>>>>>>>>>>> pointer dereference.
> >>>>>>>>>>> I'll look into this.
> >>>>>>>>>>>
> >>>>>>>>>>> I can reproduce this easily with i2c-hid + hid-multitouch following your
> >>>>>>>>>>> directions.
> >>>>>>>>>> Can you try the below patch?
> >>>>>>>>>>
> >>>>>>>>>> I think we shouldn't free buffers yet in ->stop() because we need the
> >>>>>>>>>> command buffer sending power commands to the device. Also it seems that
> >>>>>>>>>> ->start() re-allocates buffers anyway if maximum size increases.
> >>>>>>>>>>
> >>>>>>>>>> It shouldn't even leak memory as we release buffers at ->remove()
> >>>>>>>>>> anyway.
> >>>>>>>>>>
> >>>>>>>>>> diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
> >>>>>>>>>> index 62cec01937ea..68a8c938feea 100644
> >>>>>>>>>> --- a/drivers/hid/i2c-hid/i2c-hid.c
> >>>>>>>>>> +++ b/drivers/hid/i2c-hid/i2c-hid.c
> >>>>>>>>>> @@ -705,12 +705,7 @@ static int i2c_hid_start(struct hid_device *hid)
> >>>>>>>>>>
> >>>>>>>>>> static void i2c_hid_stop(struct hid_device *hid)
> >>>>>>>>>> {
> >>>>>>>>>> - struct i2c_client *client = hid->driver_data;
> >>>>>>>>>> - struct i2c_hid *ihid = i2c_get_clientdata(client);
> >>>>>>>>>> -
> >>>>>>>>>> hid->claimed = 0;
> >>>>>>>>>> -
> >>>>>>>>>> - i2c_hid_free_buffers(ihid);
> >>>>>>>>>> }
> >>>>>>>>>>
> >>>>>>>>>> static int i2c_hid_open(struct hid_device *hid)
> >>>>>>>>> Yes, it works, thanks.
> >>>>>>>>>
> >>>>>>>>> This change seems to also prevent kernel ooops when I unload either
> >>>>>>>>> i2c-hid or i2c-designware-platform while the touchpad is in use,
> >>>>>>>>> thing that is likely to happen because of the other bug I reported.
> >>>>>>>>>
> >>>>>>>>> Speaking of it, does any of you have any suggestion on how to debug it?
> >>>>>>>> I was able to reproduce the initial issue by unloading hid-rmi and
> >>>>>>>> i2c-hid while holding my fingers on the touchpad. Mika's patch fixes it
> >>>>>>>> for me.
> >>>>>>>>
> >>>>>>>> For the original bug, you can modprobe i2c-hid debug=1 and we can see
> >>>>>>>> what data the touchpad is reporting. That might help narrowing down if
> >>>>>>>> it's noise which the touchpad thinks are fingers or if there is a
> >>>>>>>> problem with the I2C lines causing spurious interrupts.
> >>>>>>>>
> >>>>>>>> Andrew
> >>>>>>> I've already tried to do that and here what I got:
> >>>>>>>
> >>>>>>> When I release the finger, the last message is repeated 81 times.
> >>>>>>> If the byte containing informations about the width of the finger
> >>>>>>> becomes equal to either c0 or 0c at least once, the last message is
> >>>>>>> repeated indefinitely and changes as soon as I start using the touchpad.
> >>>>>>> The only way to stop it is to unload and reload i2c-hid.
> >>>>>> The reports before log throttling kicks in would still be useful. For
> >>>>>> instance c0 is outside of the range of finger width which we report so
> >>>>>> something is wrong there. But, the touchpad should stop interrupting
> >>>>>> once the finger is lifted. The fact that subsequent reads are reporting
> >>>>>> the same data does sound like a problem with I2C getting confused and
> >>>>>> continuously interrupting and reading the old finger data. I am also
> >>>>>> curious about the value of the byte after the report id.
> >>>>>>
> >>>>>> Andrew
> >>>>> If I'm not wrong c0 means that the width is 12 on y axis, while 0c means
> >>>>> that the width is 12 on the x axis.
> >>>> You are correct! I forgot width was 4 bits for X and Y in the same byte.
> >>>> That makes more sense.
> >>>>
> >>>>> I have to correct myself. The important thing is that the byte is either
> >>>>> cx or xc, where x is anything below c.
> >>>>>
> >>>>> Another correction. Sometimes unloading i2c-hid is not enough, I have to
> >>>>> first disable the touchpad with xinput and then unload i2c-hid. If I
> >>>>> don't do it, the messages starts reappearing as soon as I reload i2c-hid.
> >>>>>
> >>>>> I did several tests in the past months and I'm quite sure that the bug
> >>>>> happens only past xc/cy.
> >>>> This maybe coincidental. It is not obvious to me why a certain width
> >>>> value would cause the symptoms described.
> >>> Yes, I don't deny it. This is just a constant I found in my tests.
> >>>
> >>>>> Here few lines right before the bug. The last line is repeated indefinitely:
> >>>>>
> >>>>> [ 1983.527097] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 61 0a 5f 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.537211] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 63 0a 60 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.547329] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 64 0a 60 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.557486] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 66 0a 60 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.567663] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 67 5b 68 0a 60 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.577719] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 6a 0a 61 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.587852] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 67 5b 6b 0a 61 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.598001] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 67 5b 6e 0a 62 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.608215] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 68 5b 61 0a 62 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.618288] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 68 5b 64 0b 63 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.628493] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 68 5b 67 0b 63 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.638552] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 68 5b 69 0b 64 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.648663] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 68 5b 6c 0b 64 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.658789] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 68 5b 6f 0b 64 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.668923] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 61 0b 65 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.678819] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 64 0b 65 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.689230] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 66 0b 65 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.699435] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 69 5b 68 0b 65 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.709502] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 6a 0b 66 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.719574] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 6c 0b 66 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.729713] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 69 5b 6e 0b 66 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.739863] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6a 5b 60 0b 66 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.750001] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6a 5b 62 0b 66 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.760150] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6a 5b 64 0b 67 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.770291] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6a 5b 66 0b 67 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.780445] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6a 5b 68 0b 67 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.790490] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6a 5b 5a 0b 68 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.800667] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6a 5b 4e 0c 69 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.810691] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 31 0c 69 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.820963] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 24 0c 6a 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.831071] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 17 0c 6a 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.841178] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 09 0c 6a 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.851325] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 0b 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.861435] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6b 5b 0d 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.871566] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6b 5b 0f 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.881735] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 01 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.891975] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 03 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.902073] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 05 0c 6c 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.912155] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 07 0c 6b 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.922224] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 09 0c 6c 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.932364] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 0b 0c 6c 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.942480] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6c 5b 0d 0c 6c 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.952612] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6c 5b 0f 0c 6c 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.962774] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6d 5a f1 0d 6d 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.972932] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6d 5a f3 0d 6e 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.982872] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6d 5a f6 0d 6f 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1983.993194] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6d 5a f9 0d 6f 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.003295] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6d 5a fc 0d 6f 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.013511] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6d 5a ff 0d 70 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.023590] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6e 5a f2 0d 70 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.033747] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6e 5a f5 0e 71 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.043850] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6e 5a f8 0e 71 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.053873] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6e 5a fb 0e 71 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.064077] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6e 5a fe 0e 72 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.074207] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a f1 0e 72 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.084425] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 6f 5a f3 0e 72 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.094533] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a f6 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.104629] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a f8 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.114742] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a fa 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.124890] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a fc 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.135006] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 6f 5a fe 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.145149] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 70 5a f0 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.155317] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 70 5a e2 0e 73 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.165380] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 70 5a d4 0d 74 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.175532] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 70 5a d6 0d 74 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.185409] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 70 5a d8 0d 75 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.195761] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 70 5a db 0d 75 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.205909] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 70 5a dd 0d 75 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.216034] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 71 5a d0 0e 76 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.226198] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 71 5a d3 0e 77 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.236301] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 71 5a d6 0e 77 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.246520] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 71 5a cb 0f 79 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.256573] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 01 00 72 5a b1 0e 78 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.266697] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 72 5a a7 0e 77 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.276823] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 72 5a 6d 0d 72 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.286921] i2c_hid i2c-DLL060A:00: input: 20 00 0c 0c 01 00 73 59 96 0a 5a 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.296888] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 00 00 73 59 96 00 00 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.306825] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 00 00 73 59 96 00 00 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>>> [ 1984.316980] i2c_hid i2c-DLL060A:00: input: 20 00 0c 04 00 00 73 59 96 00 00 03 09 40 00 00 90 86 1d 00 00 00 00 00 00 00 00 00 00 00 00 00
> >>>> The last report which repeats indicates that no fingers are present.
> >>>> But, the click button is generating the interrupt and it is reporting
> >>>> that it is in the down position. Could the click button be getting stuck
> >>>> down? That would also explain why the data in the report is not
> >>>> changing. Could you be bumping the touchpad with your palm which is
> >>>> causing the click button to get stuck in the down position? That might
> >>>> also explain the large width value. Our max width is 15, so 12 would
> >>>> typically indicate a contact larger then a normal finger contact. That
> >>>> would explain the width of 12 showing up when this happens.
> >>> Yes, that's not a normal finger touch and the reported width seems
> >>> quite accurate to me. There are no clicks involved, laying the side of
> >>> my thumb gently on the top part of the clickpad (from where even voluntary
> >>> clicks are hard to obtain) is enough to trigger the bug. If a click is
> >>> reported, than something is really wrong.
> >> Do the reports look the same? With the repeated reports starting with
> >> "20 00 0c 04"?
> > I'm not sure I understood exactly what you want to know, so this might
> > not answer your questions.
> >
> > All the repeated messages look like this:
> >
> > 20 00 0c 04 00 00 27 57 fa 00 00 07 8a 0c 00 00 7e 87 eb 00 00 aa 8f 37 00 00 61 4d f1 00 00 00
> >
> > The values equal to zero are always equal to zero when there are no
> > fingers on the touchpad. The non-zero values are equal to the last
> > valid value recorded and don't change when the fingers are released.
> >
> > To get the above line I touched the touchpad with 5 fingers so that
> > all the bytes (except the last one which is different from zero on
> > click release) were used.
>
> Yes, that was the information I was looking for. But, this must not be
> my day since it turns out I misremembered what 0x4 stood for and this is
> unrelated to the click button. You can ignore everything I said about
> the click button =)
>
> The report you have above is actually a finger lift report which
> indicates that all of the fingers left the touchpad. I checked the
> firmware configuration for this touchpad and it will repeat the lift
> report probably about 40 times. This is the expected behavior. However,
> you reported earlier that the message had been repeated 81 times? That
> seems a bit high and it would not explain why it gets repeated indefinitely.
>
> You can try disabling the repeating finger lift reports and see if that
> helps. To do that you need to download a utility at:
> https://github.com/aduggan/rmi4utils
>
> After building it run:
> $ sudo ./rmihidtool -r 0x45 1 /dev/hidraw0
> This should print out 0x78 assuming the register address is what I
> expect. If not I can send further instructions on how to figure that out.
>
> To disable the repeating lift report run:
> $ sudo ./rmihidtool -w 0x45 0x38 /dev/hidraw0
>
> After you do that there should only be one finger lift report.
Yes, this disables the repeating lift report, but the bug is still there.
> Also, if you can get the firmware id from your touchpad that would also
> be useful.
>
> $ sudo ./rmihidtool -f /dev/hidraw0
firmware id: 1522295
^ permalink raw reply
* Re: [PATCH v2] HID: rmi: Scan the report descriptor to determine if the device is suitable for the hid-rmi driver
From: Jiri Kosina @ 2014-12-12 9:44 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Andrew Duggan, linux-input, linux-kernel@vger.kernel.org,
Benjamin Tissoires
In-Reply-To: <CAN+gG=GLcmMFxpScE4h6mrEruNTOFXhJE9xRB16fXds1du3A5A@mail.gmail.com>
On Wed, 10 Dec 2014, Benjamin Tissoires wrote:
> With the minors comments I expressed, this patch is:
> Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Andrew, could you please resend v2 of the patch with Benjamin's comments
addressed?
Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* [PATCH v6 0/2] Add regulator-haptic driver
From: Jaewon Kim @ 2014-12-12 10:32 UTC (permalink / raw)
To: Dmitry Torokhov, Kukjin Kim
Cc: linux-kernel, linux-samsung-soc, linux-input, Chanwoo Choi,
Jaewon Kim
This patch series adds regulator-haptic driver.
The regulator-haptic has haptic motor and it is controlled by
voltage of regulator via force feedback framework.
Changes in v6:
- prevent racing condition
Changes in v5:
- give preference to platform data
Changes in v4:
- _regulator_get() -> _regulator_get_exclusive()
Changes in v3:
- fix typo in Documentation
- add define in header file
Changes in v2:
- remove driver owner
- merge enable/disable function
- support platform data
- fix wrong suspends_state check in regulator_haptic_resume()
Jaewon Kim (2):
Input: add regulator haptic driver
ARM: dts: Add regulator-haptic device node for exynos3250-rinato
.../devicetree/bindings/input/regulator-haptic.txt | 21 ++
arch/arm/boot/dts/exynos3250-rinato.dts | 7 +
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/regulator-haptic.c | 259 ++++++++++++++++++++
include/linux/input/regulator-haptic.h | 31 +++
6 files changed, 330 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/regulator-haptic.txt
create mode 100644 drivers/input/misc/regulator-haptic.c
create mode 100644 include/linux/input/regulator-haptic.h
--
1.7.9.5
^ permalink raw reply
* [PATCH v6 2/2] ARM: dts: Add haptic node for exynos3250-rinato
From: Jaewon Kim @ 2014-12-12 10:32 UTC (permalink / raw)
To: Dmitry Torokhov, Kukjin Kim
Cc: linux-kernel, linux-samsung-soc, linux-input, Chanwoo Choi,
Jaewon Kim
In-Reply-To: <1418380349-32588-1-git-send-email-jaewon02.kim@samsung.com>
This patch adds regulator-haptic device node controlled by regulator.
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
---
arch/arm/boot/dts/exynos3250-rinato.dts | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 84380fa..da03005 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -104,6 +104,13 @@
};
};
};
+
+ haptics {
+ compatible = "regulator-haptic";
+ haptic-supply = <&motor_reg>;
+ min-microvolt = <1100000>;
+ max-microvolt = <2700000>;
+ };
};
&adc {
--
1.7.9.5
^ permalink raw reply related
* [PATCH v6 1/2] Input: add regulator haptic driver
From: Jaewon Kim @ 2014-12-12 10:32 UTC (permalink / raw)
To: Dmitry Torokhov, Kukjin Kim
Cc: linux-kernel, linux-samsung-soc, linux-input, Chanwoo Choi,
Jaewon Kim, Hyunhee Kim
In-Reply-To: <1418380349-32588-1-git-send-email-jaewon02.kim@samsung.com>
This patch adds support for haptic driver controlled by
voltage of regulator. And this driver support for
Force Feedback interface from input framework
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Pankaj Dubey <pankaj.dubey@samsung.com>
---
.../devicetree/bindings/input/regulator-haptic.txt | 21 ++
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/regulator-haptic.c | 259 ++++++++++++++++++++
include/linux/input/regulator-haptic.h | 31 +++
5 files changed, 323 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/regulator-haptic.txt
create mode 100644 drivers/input/misc/regulator-haptic.c
create mode 100644 include/linux/input/regulator-haptic.h
diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.txt b/Documentation/devicetree/bindings/input/regulator-haptic.txt
new file mode 100644
index 0000000..3ed1c7e
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/regulator-haptic.txt
@@ -0,0 +1,21 @@
+* Regulator Haptic Device Tree Bindings
+
+Required Properties:
+ - compatible : Should be "regulator-haptic"
+ - haptic-supply : Power supply to the haptic motor.
+ [*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+ - max-microvolt : The maximum voltage value supplied to the haptic motor.
+ [The unit of the voltage is a micro]
+
+ - min-microvolt : The minimum voltage value supplied to the haptic motor.
+ [The unit of the voltage is a micro]
+
+Example:
+
+ haptics {
+ compatible = "regulator-haptic";
+ haptic-supply = <&motor_regulator>;
+ max-microvolt = <2700000>;
+ min-microvolt = <1100000>;
+ };
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 23297ab..e5e556d 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -394,6 +394,17 @@ config INPUT_CM109
To compile this driver as a module, choose M here: the module will be
called cm109.
+config INPUT_REGULATOR_HAPTIC
+ tristate "regulator haptics support"
+ select INPUT_FF_MEMLESS
+ help
+ This option enables device driver support for the haptic controlled
+ by regulator. This driver supports ff-memless interface
+ from input framework.
+
+ To compile this driver as a module, choose M here: the
+ module will be called regulator-haptic.
+
config INPUT_RETU_PWRBUTTON
tristate "Retu Power button Driver"
depends on MFD_RETU
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 19c7603..1f135af 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
+obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
new file mode 100644
index 0000000..2fa94bc
--- /dev/null
+++ b/drivers/input/misc/regulator-haptic.c
@@ -0,0 +1,259 @@
+/*
+ * Regulator haptic driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/input/regulator-haptic.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#define MAX_MAGNITUDE_SHIFT 16
+
+struct regulator_haptic {
+ struct device *dev;
+ struct input_dev *input_dev;
+ struct regulator *regulator;
+
+ struct work_struct work;
+ struct mutex mutex;
+
+ bool enabled;
+ bool suspend_state;
+ unsigned int max_volt;
+ unsigned int min_volt;
+ unsigned int intensity;
+ unsigned int magnitude;
+};
+
+static void regulator_haptic_enable(struct regulator_haptic *haptic, bool state)
+{
+ int error;
+
+ if (haptic->enabled == state)
+ return;
+
+ if (state)
+ error = regulator_enable(haptic->regulator);
+ else
+ error = regulator_disable(haptic->regulator);
+ if (error) {
+ dev_err(haptic->dev, "cannot enable regulator\n");
+ return;
+ }
+
+ haptic->enabled = state;
+}
+
+static void regulator_haptic_work(struct work_struct *work)
+{
+ struct regulator_haptic *haptic = container_of(work,
+ struct regulator_haptic, work);
+ int error;
+
+ if (haptic->suspend_state)
+ return;
+
+ mutex_lock(&haptic->mutex);
+
+ error = regulator_set_voltage(haptic->regulator,
+ haptic->intensity + haptic->min_volt, haptic->max_volt);
+ if (error) {
+ dev_err(haptic->dev, "cannot set regulator voltage\n");
+ goto err;
+ }
+
+ if (haptic->magnitude)
+ regulator_haptic_enable(haptic, true);
+ else
+ regulator_haptic_enable(haptic, false);
+
+err:
+ mutex_unlock(&haptic->mutex);
+}
+
+static int regulator_haptic_play_effect(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct regulator_haptic *haptic = input_get_drvdata(input);
+ u64 volt_mag_multi;
+
+ haptic->magnitude = effect->u.rumble.strong_magnitude;
+ if (!haptic->magnitude)
+ haptic->magnitude = effect->u.rumble.weak_magnitude;
+
+
+ volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) *
+ haptic->magnitude;
+ haptic->intensity = (unsigned int)(volt_mag_multi >>
+ MAX_MAGNITUDE_SHIFT);
+
+ schedule_work(&haptic->work);
+
+ return 0;
+}
+
+static void regulator_haptic_close(struct input_dev *input)
+{
+ struct regulator_haptic *haptic = input_get_drvdata(input);
+
+ cancel_work_sync(&haptic->work);
+ regulator_haptic_enable(haptic, false);
+}
+
+#ifdef CONFIG_OF
+static int regulator_haptic_parse_dt(struct regulator_haptic *haptic)
+{
+ struct device_node *node = haptic->dev->of_node;
+ int error;
+
+ error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt);
+ if (error) {
+ dev_err(haptic->dev, "cannot parse max-microvolt\n");
+ return error;
+ }
+
+ error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt);
+ if (error) {
+ dev_err(haptic->dev, "cannot parse min-microvolt\n");
+ return error;
+ }
+
+ return 0;
+}
+#else
+static int regulator_haptic_parse_dt(struct regulator_haptic *haptic)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static int regulator_haptic_probe(struct platform_device *pdev)
+{
+ struct regulator_haptic *haptic;
+ struct regulator_haptic_data *data = dev_get_platdata(&pdev->dev);
+ struct input_dev *input_dev;
+ int error;
+
+ haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
+ if (!haptic)
+ return -ENOMEM;
+
+ haptic->dev = &pdev->dev;
+ haptic->enabled = false;
+ haptic->suspend_state = false;
+ mutex_init(&haptic->mutex);
+ INIT_WORK(&haptic->work, regulator_haptic_work);
+
+ if (!data) {
+ if (pdev->dev.of_node) {
+ error = regulator_haptic_parse_dt(haptic);
+ if (error) {
+ dev_err(&pdev->dev, "failed to parse device tree\n");
+ return error;
+ }
+ } else {
+ dev_err(&pdev->dev, "failed to get platdata\n");
+ return -EINVAL;
+ }
+ } else {
+ haptic->regulator = data->regulator;
+ haptic->max_volt = data->max_volt;
+ haptic->min_volt = data->min_volt;
+ }
+
+ haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic");
+ if (IS_ERR(haptic->regulator)) {
+ dev_err(&pdev->dev, "failed to get regulator\n");
+ return PTR_ERR(haptic->regulator);
+ }
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ haptic->input_dev = input_dev;
+ haptic->input_dev->name = "regulator-haptic";
+ haptic->input_dev->dev.parent = &pdev->dev;
+ haptic->input_dev->close = regulator_haptic_close;
+ input_set_drvdata(haptic->input_dev, haptic);
+ input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
+
+ error = input_ff_create_memless(input_dev, NULL,
+ regulator_haptic_play_effect);
+ if (error) {
+ dev_err(&pdev->dev, "failed to create force-feedback\n");
+ return error;
+ }
+
+ error = input_register_device(haptic->input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ return error;
+ }
+
+ platform_set_drvdata(pdev, haptic);
+
+ return 0;
+}
+
+static int __maybe_unused regulator_haptic_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+
+ mutex_lock(&haptic->mutex);
+ if (haptic->enabled) {
+ regulator_haptic_enable(haptic, false);
+ haptic->suspend_state = true;
+ }
+ mutex_unlock(&haptic->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused regulator_haptic_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+
+ if (haptic->suspend_state) {
+ regulator_haptic_enable(haptic, true);
+ haptic->suspend_state = false;
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
+ regulator_haptic_suspend, regulator_haptic_resume);
+
+static struct of_device_id regulator_haptic_dt_match[] = {
+ { .compatible = "regulator-haptic" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver regulator_haptic_driver = {
+ .probe = regulator_haptic_probe,
+ .driver = {
+ .name = "regulator-haptic",
+ .of_match_table = regulator_haptic_dt_match,
+ .pm = ®ulator_haptic_pm_ops,
+ },
+};
+module_platform_driver(regulator_haptic_driver);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
+MODULE_DESCRIPTION("Regulator haptic driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/input/regulator-haptic.h b/include/linux/input/regulator-haptic.h
new file mode 100644
index 0000000..05ae038
--- /dev/null
+++ b/include/linux/input/regulator-haptic.h
@@ -0,0 +1,31 @@
+/*
+ * Regulator Haptic Platform Data
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _REGULATOR_HAPTIC_H
+#define _REGULATOR_HAPTIC_H
+
+/*
+ * struct regulator_haptic_data - Platform device data
+ *
+ * @regulator: Power supply to the haptic motor
+ * @max_volt: maximum voltage value supplied to the haptic motor.
+ * <The unit of the voltage is a micro>
+ * @min_volt: minimum voltage value supplied to the haptic motor.
+ * <The unit of the voltage is a micro>
+ */
+struct regulator_haptic_data {
+ struct regulator *regulator;
+ unsigned int max_volt;
+ unsigned int min_volt;
+};
+
+#endif /* _REGULATOR_HAPTIC_H */
--
1.7.9.5
^ permalink raw reply related
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: David Herrmann @ 2014-12-12 11:05 UTC (permalink / raw)
To: Andy Lutomirski; +Cc: Jiri Kosina, open list:HID CORE LAYER, Benjamin Tissoires
In-Reply-To: <CALCETrXcHKwBuOA0wpFzgSe8Z9+t8LyaB7U+vdgVsR=YZc+GjQ@mail.gmail.com>
Hi
On Thu, Dec 11, 2014 at 6:36 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> It happens during driver probe. I don't set GET_REPORT to my device
> -- the protocol consists solely of SET_REPORT from the driver followed
> by an asynchronous (but generally reasonably quick) report back from
> the device.
>
> During probe, I set INIT, and the device responds by saying "I'm a
> device. I speak this version of the protocol.
>
> Shouldn't that code be more like:
>
> mutex_lock(whatever);
> if (driver loaded)
> deliver the report;
> mutex_unlock(whatever);
>
> and then the core could hold the lock briefly as well when probing or
> in hid_hw_open/hid_hw_close.
If we only lock around a boolean flag, we need a wait-queue to make
sure a driver-removal does not run before driver-probe is done. I
haven't looked at it in detail, maybe we're only called from
driver-core so we already have this guarantee. Not sure. Feel free to
send patches.
So far, the solution is to use hid_device_io_start() and
hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
->probe(). Maybe your idea is the way to go, but unless someone
implements it, we're stuck with the current code.
Please have a look at some other drivers in drivers/hid/ to see how
hid_device_io_start() / hid_device_io_stop() is used. You should be
fine by just calling hid_device_io_start() from ->probe() after your
context setup is done and you called hid_hw_start().
> (Also, shouldn't hid_hw_open have some kind of reference counting to
> avoid interference between hidraw and real drivers? Or does that
> already work correctly somehow?)
Kinda.. currently, hidraw is treated as a passive client. That is, the
hid-device-driver manages the device and hidraw does not interfere. If
no device-driver is loaded, hid_hw_start/stop is called by hid-core,
so hidraw will usually work fine. However, if a device-driver is
loaded, it gets exclusive access to the hardware so is also
responsible of hid_hw_start/stop. hidraw will follow its lead. Note
that this is _required_ by some devices as vendors are really crappy
in writing HID firmware. Think like devices which need an
initialization after transport-layer setup, or they will timeout... or
continuous beacon events... It's stuff like that.. Not sure whether we
still have drivers for broken devices like that, but afaik that's
where this originated.
Thanks
David
^ permalink raw reply
* Re: [PATCH v2] HID: logitech-hidpp: prefix the name with Logitech
From: Peter Wu @ 2014-12-12 11:35 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Jiri Kosina, Nestor Lopez Casado, Peter Hutterer, linux-input,
linux-kernel
In-Reply-To: <1418337599-10239-1-git-send-email-benjamin.tissoires@redhat.com>
On Thursday 11 December 2014 17:39:59 Benjamin Tissoires wrote:
> Current names are reported as "K750", "M705", and it can be misleading
> for the users when they look at their input device list.
>
> Prefixing the names with "Logitech " makes things better.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Reviewed-by: Peter Wu <peter@lekensteyn.nl>
I have not tested this one, but the approach looks correct. What I have
also been thinking of is the possibility that Logitech adds "LOGITECH"
or "Logicool" (the Japanese trademark) before devices, but I think that
is unlikely so there is no need to check for other strings.
> ---
>
> Changes in v2:
> - renamed PREFIX_SIZE into PREFIX_LENGTH
> - changed "name_length + PREFIX_LENGTH;" into "PREFIX_LENGTH + name_length;"
> - rebased on Peter's last patch series
>
> drivers/hid/hid-logitech-hidpp.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index 2f420c0..274dbb7 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -282,6 +282,33 @@ static inline bool hidpp_report_is_connect_event(struct hidpp_report *report)
> (report->rap.sub_id == 0x41);
> }
>
> +/**
> + * hidpp_prefix_name() prefixes the current given name with "Logitech ".
> + */
> +static void hidpp_prefix_name(char **name, int name_length)
> +{
> +#define PREFIX_LENGTH 9 /* "Logitech " */
> +
> + int new_length;
> + char *new_name;
> +
> + if (name_length > PREFIX_LENGTH &&
> + strncmp(*name, "Logitech ", PREFIX_LENGTH) == 0)
> + /* The prefix has is already in the name */
> + return;
> +
> + new_length = PREFIX_LENGTH + name_length;
> + new_name = kzalloc(new_length, GFP_KERNEL);
> + if (!new_name)
> + return;
> +
> + snprintf(new_name, new_length, "Logitech %s", *name);
> +
> + kfree(*name);
> +
> + *name = new_name;
> +}
> +
> /* -------------------------------------------------------------------------- */
> /* HIDP++ 1.0 commands */
> /* -------------------------------------------------------------------------- */
> @@ -321,6 +348,10 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev)
> return NULL;
>
> memcpy(name, &response.rap.params[2], len);
> +
> + /* include the terminating '\0' */
> + hidpp_prefix_name(&name, len + 1);
> +
> return name;
> }
>
> @@ -498,6 +529,9 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
> index += ret;
> }
>
> + /* include the terminating '\0' */
> + hidpp_prefix_name(&name, __name_length + 1);
> +
> return name;
> }
>
>
--
Kind regards,
Peter
https://lekensteyn.nl
^ permalink raw reply
* [PATCH] HID: i2c-hid: Do not free buffers in i2c_hid_stop()
From: Mika Westerberg @ 2014-12-12 12:01 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Gabriele Mazzotta, Jiri Kosina, Benjamin Tissoires,
aduggan, Mika Westerberg
When a hid driver that uses i2c-hid as transport is unloaded, the hid core
will call i2c_hid_stop() which releases all the buffers associated with the
device. This includes also the command buffer.
Now, when the i2c-hid driver itself is unloaded it tries to power down the
device by sending it PWR_SLEEP command. Since the command buffer is already
released we get following crash:
[ 79.691459] BUG: unable to handle kernel NULL pointer dereference at (null)
[ 79.691532] IP: [<ffffffffa05bc049>] __i2c_hid_command+0x49/0x310 [i2c_hid]
...
[ 79.693467] Call Trace:
[ 79.693494] [<ffffffff810424e1>] ? __unmask_ioapic+0x21/0x30
[ 79.693537] [<ffffffff81042855>] ? unmask_ioapic+0x25/0x40
[ 79.693581] [<ffffffffa05bc35b>] ? i2c_hid_set_power+0x4b/0xa0 [i2c_hid]
[ 79.693632] [<ffffffffa05bc3cf>] ? i2c_hid_runtime_resume+0x1f/0x30 [i2c_hid]
[ 79.693689] [<ffffffff814c08fb>] ? __rpm_callback+0x2b/0x70
[ 79.693733] [<ffffffff814c0961>] ? rpm_callback+0x21/0x90
[ 79.693776] [<ffffffff814c0dec>] ? rpm_resume+0x41c/0x600
[ 79.693820] [<ffffffff814c1e1c>] ? __pm_runtime_resume+0x4c/0x80
[ 79.693868] [<ffffffff814b8588>] ? __device_release_driver+0x28/0x100
[ 79.693917] [<ffffffff814b8d90>] ? driver_detach+0xa0/0xb0
[ 79.693959] [<ffffffff814b82cc>] ? bus_remove_driver+0x4c/0xb0
[ 79.694006] [<ffffffff810d1cfd>] ? SyS_delete_module+0x11d/0x1d0
[ 79.694054] [<ffffffff8165f107>] ? int_signal+0x12/0x17
[ 79.694095] [<ffffffff8165ee69>] ? system_call_fastpath+0x12/0x17
Fix this so that we only free buffers when the i2c-hid driver itself is
removed.
Fixes: 34f439e4afcd ("HID: i2c-hid: add runtime PM support")
Reported-by: Gabriele Mazzotta <gabriele.mzt@gmail.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 5 -----
1 file changed, 5 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 747d54421e73..a58c6a8d4f93 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -702,12 +702,7 @@ static int i2c_hid_start(struct hid_device *hid)
static void i2c_hid_stop(struct hid_device *hid)
{
- struct i2c_client *client = hid->driver_data;
- struct i2c_hid *ihid = i2c_get_clientdata(client);
-
hid->claimed = 0;
-
- i2c_hid_free_buffers(ihid);
}
static int i2c_hid_open(struct hid_device *hid)
--
2.1.3
^ permalink raw reply related
* Re: [PATCHv2 0/3] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: Hans de Goede @ 2014-12-12 13: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>
[-- Attachment #1: Type: text/plain, Size: 2718 bytes --]
Hi,
On 07-12-14 00:15, vishnupatekar wrote:
> Here is v2 of SUNXI PS2 controller support patch-set as with v1.
So as promised I've run this on an A10 board, with a small fix to
the interrupt property in the sun4i.dtsi file this works as is.
This means that the sun7i compat should be dropped, and the sun4i
compat used everywhere.
I've created 3 fixup patches to do this, note one also renames / moves
the bindings file as it is in the wrong place.
I've attached the 3 fixup patches, pleasesquash these into your
existing patches before posting the next version.
Thanks & Regards,
Hans
>
> 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
>
--
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: 0001-FIXUP-sunxi-dts-bindings-input-ps2-bindings-for-A10-.patch --]
[-- Type: text/x-patch, Size: 3292 bytes --]
>From 85105ec25cfb0dcff102e579e00a0a6c38ac34e9 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date: Fri, 12 Dec 2014 14:05:56 +0100
Subject: [PATCH v2 1/4] FIXUP: "sunxi:dts-bindings:input:ps2 bindings for
A10/A20 ps2."
2 fixups for: "sunxi:dts-bindings:input:ps2 bindings for A10/A20 ps2."
1) dt bindings should use the compat string for the earliest version of the
hardware which has the relevant hardware block, unless there are differences,
the A10 and A20 ps2 controllers are identical, so for both sun4i-a10-ps2
should be used as compat string.
2) ps2 / serio bindings belong under Documentation/devicetree/bindings/serio
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
.../bindings/input/allwinner,sunxi-ps2.txt | 23 ----------------------
.../bindings/serio/allwinner,sun4i-a10-ps2.txt | 22 +++++++++++++++++++++
2 files changed, 22 insertions(+), 23 deletions(-)
delete mode 100644 Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.txt
diff --git a/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt b/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
deleted file mode 100644
index 3a8919a..0000000
--- a/Documentation/devicetree/bindings/input/allwinner,sunxi-ps2.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-* 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";
- };
diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.txt
new file mode 100644
index 0000000..c93ca90
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-a10-ps2.txt
@@ -0,0 +1,22 @@
+* Device tree bindings for Allwinner A10, A20 PS2 host controller
+
+A10 PS2 is dual role controller (PS2 host and PS2 device). These bindings are
+for the 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 : "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,sun4i-a10-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <0 62 4>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
--
2.1.0
[-- Attachment #3: 0002-FIXUP-sunxi-drivers-input-ps2-Added-sunxi-A10-A20-ps.patch --]
[-- Type: text/x-patch, Size: 1205 bytes --]
>From 0eecd5e763278a59c4533e576ac1c9616310c21e Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date: Fri, 12 Dec 2014 14:11:56 +0100
Subject: [PATCH v2 2/4] FIXUP: "sunxi:drivers:input:ps2 Added sunxi A10/A20
ps2 driver"
dt bindings should use the compat string for the earliest version of the
hardware which has the relevant hardware block, unless there are differences,
the A10 and A20 ps2 controllers are identical, so for both sun4i-a10-ps2
should be used as compat string, drop the sun7i-a20-ps2 compat string.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
drivers/input/serio/sunxi-ps2.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/input/serio/sunxi-ps2.c b/drivers/input/serio/sunxi-ps2.c
index 4cd89ae..cb89d80 100644
--- a/drivers/input/serio/sunxi-ps2.c
+++ b/drivers/input/serio/sunxi-ps2.c
@@ -340,7 +340,6 @@ static int sunxips2_remove(struct platform_device *pdev)
/* 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", },
{ },
};
--
2.1.0
[-- Attachment #4: 0003-FIXUP-ARM-dts-sunxi-ps2-dt-nodes-for-A10-A20-PS2-con.patch --]
[-- Type: text/x-patch, Size: 2304 bytes --]
>From 45985183f3e96adf1c846c7bbde32647367024dc Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date: Fri, 12 Dec 2014 14:01:43 +0100
Subject: [PATCH v2 3/4] FIXUP: "ARM:dts:sunxi:ps2 dt nodes for A10/A20 PS2
controller."
2 fixups for: "ARM:dts:sunxi:ps2 dt nodes for A10/A20 PS2 controller."
1) Fixup the sun4i ps/2 nodes interrupt property, sun4i interrupts take
only 1 specifier
2) dt bindings should use the compat string for the earliest version of the
hardware which has the relevant hardware block, unless there are differences,
the A10 and A20 ps2 controllers are identical, so for both sun4i-a10-ps2
should be used as compat string, update the sun7i.dtsi ps2 entries to
use the sun4i-a10-ps2 compat string.
Signed-off-by: Hans de Goede <hdegoede-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 4 ++--
arch/arm/boot/dts/sun7i-a20.dtsi | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index c04c117..e8cd6db 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -818,14 +818,14 @@
ps20: ps2@0x01c2a000 {
compatible = "allwinner,sun4i-a10-ps2";
reg = <0x01c2a000 0x400>;
- interrupts = <0 62 4>;
+ interrupts = <62>;
clocks = <&apb1_gates 6>;
status = "disabled";
};
ps21: ps2@0x01c2a400 {
compatible = "allwinner,sun4i-a10-ps2";
reg = <0x01c2a400 0x400>;
- interrupts = <0 63 4>;
+ interrupts = <63>;
clocks = <&apb1_gates 7>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 4417c8c3..d54d684 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1114,14 +1114,14 @@
interrupts = <1 9 0xf04>;
};
ps20: ps2@0x01c2a000 {
- compatible = "allwinner,sun7i-a20-ps2";
+ compatible = "allwinner,sun4i-a10-ps2";
reg = <0x01c2a000 0x400>;
interrupts = <0 62 4>;
clocks = <&apb1_gates 6>;
status = "disabled";
};
ps21: ps2@0x01c2a400 {
- compatible = "allwinner,sun7i-a20-ps2";
+ compatible = "allwinner,sun4i-a10-ps2";
reg = <0x01c2a400 0x400>;
interrupts = <0 63 4>;
clocks = <&apb1_gates 7>;
^ permalink raw reply related
* Re: [PATCH v4 0/6] Touchscreen performance related fixes
From: Vignesh R @ 2014-12-12 13:48 UTC (permalink / raw)
To: Sebastian Andrzej Siewior, Nicolae Rosia
Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
Benoit Cousson, Tony Lindgren, Russell King, Jonathan Cameron,
Hartmut Knaack, richardcochran, Dmitry Torokhov, Lee Jones,
Lars-Peter Clausen, Peter Meerwald, Samuel Ortiz, Felipe Balbi,
Brad Griffis, Sanjeev Sharma, Paul Gortmaker, Jan Kardell,
devicetree, linux-kernel, linux-omap
In-Reply-To: <548A0125.6040708@linutronix.de>
On Friday 12 December 2014 02:10 AM, Sebastian Andrzej Siewior wrote:
> On 12/11/2014 09:34 PM, Nicolae Rosia wrote:
>> Hello,
>
> Hi,
>
>> Any updates on this series? I don't see it applied in [1] or [2].
>
> I manage to freeze am335x-evm with those patches and I think Vignesh
> is looking into this.
I was not able to reproduce this issue with my kernel configurations.
I am yet to try with Sebastian's ".config" file. Not been able work on this.
>
>> Regards,
>> Nicolae Rosia
>
> Sebastian
>
Regards,
Vignesh
^ permalink raw reply
* Re: [PATCH v4 0/6] Touchscreen performance related fixes
From: Catalin Crenguta @ 2014-12-12 13:55 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Nicolae Rosia, Vignesh R, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Benoit Cousson, Tony Lindgren,
Russell King, Jonathan Cameron, Hartmut Knaack, richardcochran,
Dmitry Torokhov, Lee Jones, Lars-Peter Clausen, Peter Meerwald,
Samuel Ortiz, Felipe Balbi, Brad Griffis, Sanjeev Sharma,
Paul Gortmaker, Jan Kardell, devicetree
In-Reply-To: <548A0125.6040708@linutronix.de>
Hello,
I have tried your patches by cloning [1] and copying the
relevant files over the kernel I've cloned from [2].
It compiles & runs, but I'm seeing lots of pen-down/pen-up
events when I'm not touching the screen.
Any suggestions?
Hardware: Beaglebone Black with BB-View 4.3 Cape from Farnell
[1] git clone -b tsc-devel git://git.ti.com/kernel/tsc-adc.git
(tsc-devel branch)
[2] https://github.com/beagleboard/linux/tree/3.14
^ permalink raw reply
* Re: [PATCHv2 0/3] ARM:sunxi:ps2 Added support for A10/A20 ps2 controller.
From: Vishnu Patekar @ 2014-12-12 13:55 UTC (permalink / raw)
To: linux-sunxi-/JYPxA39Uh5TLH3MbocFFw
Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-lFZ/pmaqli7XmaaqVzeoHQ, 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,
VishnuPatekar0510-Re5JQEeQqe8AvxtiuMwx3w,
hdegoede-H+wXaHxf7aLQT0dZR+AlfA
In-Reply-To: <548AEA8E.6040100-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
[-- Attachment #1.1: Type: text/plain, Size: 3156 bytes --]
Hello Hans,
Thank you for testing it on A10 board. now we have PS2 working on A10 as
well. :)
I'll include these in next version which I'm was about to send.
On Friday, December 12, 2014 6:46:25 PM UTC+5:30, Hans de Goede wrote:
>
> Hi,
>
> On 07-12-14 00:15, vishnupatekar wrote:
> > Here is v2 of SUNXI PS2 controller support patch-set as with v1.
>
> So as promised I've run this on an A10 board, with a small fix to
> the interrupt property in the sun4i.dtsi file this works as is.
>
> This means that the sun7i compat should be dropped, and the sun4i
> compat used everywhere.
>
> I've created 3 fixup patches to do this, note one also renames / moves
> the bindings file as it is in the wrong place.
>
> I've attached the 3 fixup patches, pleasesquash these into your
> existing patches before posting the next version.
>
> Thanks & Regards,
>
> Hans
>
>
> >
> > 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
> >
>
--
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 #1.2: Type: text/html, Size: 4352 bytes --]
^ permalink raw reply
* RE: [PATCH v4 0/6] Touchscreen performance related fixes
From: Griffis, Brad @ 2014-12-12 14:16 UTC (permalink / raw)
To: Catalin Crenguta, Sebastian Andrzej Siewior
Cc: Nicolae Rosia, R, Vignesh, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Benoit Cousson, Tony Lindgren,
Russell King, Jonathan Cameron, Hartmut Knaack,
richardcochran@gmail.com, Dmitry Torokhov, Lee Jones,
Lars-Peter Clausen, Peter Meerwald, Samuel Ortiz, Balbi, Felipe,
Sanjeev Sharma, Paul Gortmaker, Jan Kardell, devicetree
In-Reply-To: <CABH3fy8zCjsxARsqBf9JXOHBkzySdiqifA1KtjnGpJdBY2EikA@mail.gmail.com>
> -----Original Message-----
> From: Catalin Crenguta [mailto:catalin.crenguta@gmail.com]
> I have tried your patches by cloning [1] and copying the relevant files over
> the kernel I've cloned from [2].
> It compiles & runs, but I'm seeing lots of pen-down/pen-up events when I'm
> not touching the screen.
> Any suggestions?
How are you configuring ti,charge-delay in your dts? I've seen this behavior on some custom boards where we were using a smaller charge delay (0x400) to begin with, and by upping it to 0xb000 we resolved the issue. These patches however already specified ti,charge-delay = 0xb000 by default so this would surprise me that it's still seeing that issue. Was the touchscreen working as expected before these new patches, or does it have issues both ways?
^ permalink raw reply
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: Andy Lutomirski @ 2014-12-12 17:18 UTC (permalink / raw)
To: David Herrmann; +Cc: Benjamin Tissoires, Jiri Kosina, open list:HID CORE LAYER
In-Reply-To: <CANq1E4SVQAkyxJpiYsiLkjsET27QUK9PHTHTAqp4wQZVLKrMiw@mail.gmail.com>
On Dec 12, 2014 3:05 AM, "David Herrmann" <dh.herrmann@gmail.com> wrote:
>
> Hi
>
> On Thu, Dec 11, 2014 at 6:36 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> > It happens during driver probe. I don't set GET_REPORT to my device
> > -- the protocol consists solely of SET_REPORT from the driver followed
> > by an asynchronous (but generally reasonably quick) report back from
> > the device.
> >
> > During probe, I set INIT, and the device responds by saying "I'm a
> > device. I speak this version of the protocol.
> >
> > Shouldn't that code be more like:
> >
> > mutex_lock(whatever);
> > if (driver loaded)
> > deliver the report;
> > mutex_unlock(whatever);
> >
> > and then the core could hold the lock briefly as well when probing or
> > in hid_hw_open/hid_hw_close.
>
> If we only lock around a boolean flag, we need a wait-queue to make
> sure a driver-removal does not run before driver-probe is done. I
> haven't looked at it in detail, maybe we're only called from
> driver-core so we already have this guarantee. Not sure. Feel free to
> send patches.
Hmm. I'll look, but I may just stick with hid_device_io_start.
>
> So far, the solution is to use hid_device_io_start() and
> hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
> ->probe(). Maybe your idea is the way to go, but unless someone
> implements it, we're stuck with the current code.
That should work.
For normal HID drivers (those that don't start IO from probe), what
happens if userspace starts IO before probe returns? Does the driver
code prevent that somehow?
Thanks,
Andy
>
> Please have a look at some other drivers in drivers/hid/ to see how
> hid_device_io_start() / hid_device_io_stop() is used. You should be
> fine by just calling hid_device_io_start() from ->probe() after your
> context setup is done and you called hid_hw_start().
>
> > (Also, shouldn't hid_hw_open have some kind of reference counting to
> > avoid interference between hidraw and real drivers? Or does that
> > already work correctly somehow?)
>
> Kinda.. currently, hidraw is treated as a passive client. That is, the
> hid-device-driver manages the device and hidraw does not interfere. If
> no device-driver is loaded, hid_hw_start/stop is called by hid-core,
> so hidraw will usually work fine. However, if a device-driver is
> loaded, it gets exclusive access to the hardware so is also
> responsible of hid_hw_start/stop. hidraw will follow its lead. Note
> that this is _required_ by some devices as vendors are really crappy
> in writing HID firmware. Think like devices which need an
> initialization after transport-layer setup, or they will timeout... or
> continuous beacon events... It's stuff like that.. Not sure whether we
> still have drivers for broken devices like that, but afaik that's
> where this originated.
>
> Thanks
> David
^ permalink raw reply
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: David Herrmann @ 2014-12-12 17:21 UTC (permalink / raw)
To: Andy Lutomirski; +Cc: Benjamin Tissoires, Jiri Kosina, open list:HID CORE LAYER
In-Reply-To: <CALCETrVfvK-BhaQMyfvLndfmX+gwAwshx3vdCFa7sOr+R1Jjpw@mail.gmail.com>
Hi
On Fri, Dec 12, 2014 at 6:18 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Dec 12, 2014 3:05 AM, "David Herrmann" <dh.herrmann@gmail.com> wrote:
>>
>> So far, the solution is to use hid_device_io_start() and
>> hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
>> ->probe(). Maybe your idea is the way to go, but unless someone
>> implements it, we're stuck with the current code.
>
> That should work.
>
> For normal HID drivers (those that don't start IO from probe), what
> happens if userspace starts IO before probe returns? Does the driver
> code prevent that somehow?
It's only the async hid intr channel that is affected by this.
User-space cannot trigger any outgoing I/O on the intr channel. Only
the synchronous ctrl channel via SET_REPORT can be triggered, but due
to the synchronous nature we always allow I/O on it.
Thanks
David
^ permalink raw reply
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: Andy Lutomirski @ 2014-12-12 17:25 UTC (permalink / raw)
To: David Herrmann; +Cc: Benjamin Tissoires, Jiri Kosina, open list:HID CORE LAYER
In-Reply-To: <CANq1E4Q8+0_cLtwraK=gqFBovQoft9-0S4+ns_n9A7CinNTw7g@mail.gmail.com>
On Fri, Dec 12, 2014 at 9:21 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> On Fri, Dec 12, 2014 at 6:18 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Dec 12, 2014 3:05 AM, "David Herrmann" <dh.herrmann@gmail.com> wrote:
>>>
>>> So far, the solution is to use hid_device_io_start() and
>>> hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
>>> ->probe(). Maybe your idea is the way to go, but unless someone
>>> implements it, we're stuck with the current code.
>>
>> That should work.
>>
>> For normal HID drivers (those that don't start IO from probe), what
>> happens if userspace starts IO before probe returns? Does the driver
>> code prevent that somehow?
>
> It's only the async hid intr channel that is affected by this.
> User-space cannot trigger any outgoing I/O on the intr channel. Only
> the synchronous ctrl channel via SET_REPORT can be triggered, but due
> to the synchronous nature we always allow I/O on it.
>
I understand exactly one HID device, and that's U2F. In U2F,
userspace will (directly or indirectly) use SET_REPORT, and the device
responds immediately (ish) using the async intr channel.
--Andy
> Thanks
> David
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: David Herrmann @ 2014-12-12 17:32 UTC (permalink / raw)
To: Andy Lutomirski; +Cc: Benjamin Tissoires, Jiri Kosina, open list:HID CORE LAYER
In-Reply-To: <CALCETrW-Mt5Hqh353t3zm6Pq2kSUkw_16a2=DFHoEk=G92AU+w@mail.gmail.com>
Hi
On Fri, Dec 12, 2014 at 6:25 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Fri, Dec 12, 2014 at 9:21 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
>> Hi
>>
>> On Fri, Dec 12, 2014 at 6:18 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>>> On Dec 12, 2014 3:05 AM, "David Herrmann" <dh.herrmann@gmail.com> wrote:
>>>>
>>>> So far, the solution is to use hid_device_io_start() and
>>>> hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
>>>> ->probe(). Maybe your idea is the way to go, but unless someone
>>>> implements it, we're stuck with the current code.
>>>
>>> That should work.
>>>
>>> For normal HID drivers (those that don't start IO from probe), what
>>> happens if userspace starts IO before probe returns? Does the driver
>>> code prevent that somehow?
>>
>> It's only the async hid intr channel that is affected by this.
>> User-space cannot trigger any outgoing I/O on the intr channel. Only
>> the synchronous ctrl channel via SET_REPORT can be triggered, but due
>> to the synchronous nature we always allow I/O on it.
>>
>
> I understand exactly one HID device, and that's U2F. In U2F,
> userspace will (directly or indirectly) use SET_REPORT, and the device
> responds immediately (ish) using the async intr channel.
How does user-space issue SET_REPORT? Via hidraw? hidraw shouldn't be
used for anything but debugging right now.
The normal hid drivers are managed through hid-input.c, which
registers the input devices and syncs it up with its ->probe()
function. Most of the hid-xyz.c drivers are just quirks for
hid-input.c.
If you now invent your own layer on top, you usually don't want
hid-input.c. Instead, you register your own user-space API (for
instance via cdev_add(), or misc-devices). In those cases, you
register your devices from within ->probe() so it is up to you to
enable I/O before doing this.
I have no idea what user-space API you intend to use. Unfortunately, I
don't even know what kind of API U2F actually provides, so I cannot
even point you into the right direction. Sorry.
(btw., Documentation/hid/hid-transport.txt is an overview of how HID
transport layers work)
Thanks
David
^ permalink raw reply
* Re: [systemd-devel] Supporting U2F over HID on Linux?
From: Andy Lutomirski @ 2014-12-12 17:50 UTC (permalink / raw)
To: David Herrmann; +Cc: Benjamin Tissoires, Jiri Kosina, open list:HID CORE LAYER
In-Reply-To: <CANq1E4QATOTs0ZtQF0mT645Z5u+vxYyphq8-UbqvNAc4iNz3iQ@mail.gmail.com>
On Fri, Dec 12, 2014 at 9:32 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> On Fri, Dec 12, 2014 at 6:25 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>> On Fri, Dec 12, 2014 at 9:21 AM, David Herrmann <dh.herrmann@gmail.com> wrote:
>>> Hi
>>>
>>> On Fri, Dec 12, 2014 at 6:18 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>>>> On Dec 12, 2014 3:05 AM, "David Herrmann" <dh.herrmann@gmail.com> wrote:
>>>>>
>>>>> So far, the solution is to use hid_device_io_start() and
>>>>> hid_device_io_stop() in ->probe(). It's a hack to allow I/O during
>>>>> ->probe(). Maybe your idea is the way to go, but unless someone
>>>>> implements it, we're stuck with the current code.
>>>>
>>>> That should work.
>>>>
>>>> For normal HID drivers (those that don't start IO from probe), what
>>>> happens if userspace starts IO before probe returns? Does the driver
>>>> code prevent that somehow?
>>>
>>> It's only the async hid intr channel that is affected by this.
>>> User-space cannot trigger any outgoing I/O on the intr channel. Only
>>> the synchronous ctrl channel via SET_REPORT can be triggered, but due
>>> to the synchronous nature we always allow I/O on it.
>>>
>>
>> I understand exactly one HID device, and that's U2F. In U2F,
>> userspace will (directly or indirectly) use SET_REPORT, and the device
>> responds immediately (ish) using the async intr channel.
>
> How does user-space issue SET_REPORT? Via hidraw? hidraw shouldn't be
> used for anything but debugging right now.
Using whatever character device I end up using. That is, totally
undecided at this point.
>
> The normal hid drivers are managed through hid-input.c, which
> registers the input devices and syncs it up with its ->probe()
> function. Most of the hid-xyz.c drivers are just quirks for
> hid-input.c.
>
> If you now invent your own layer on top, you usually don't want
> hid-input.c. Instead, you register your own user-space API (for
> instance via cdev_add(), or misc-devices). In those cases, you
> register your devices from within ->probe() so it is up to you to
> enable I/O before doing this.
Yeah, I need to do that and turn off the hid-input stuff. This thing
isn't really an input device.
>
> I have no idea what user-space API you intend to use. Unfortunately, I
> don't even know what kind of API U2F actually provides, so I cannot
> even point you into the right direction. Sorry.
>
It's roughly ISO7816-3. For the uninitiated (and the ISO7816 standard
is amazingly vague), that means that the application sends a short
(<64kB) binary request to the device (with a type, two "parameters",
and a payload), and the device answers with exactly one reply packet
that has two bytes of status and a payload. These requests and
replies are fragmented into multiple HID reports.
At a higher level, there are three defined request types, one for
ping, one for key generation, and one for authentication. There are
also a couple of useful vendor-specific interfaces.
The device has a button, although the way to detect the state of the
button is to poll, using the aforementioned packet interface. I kid
you not. (This isn't quite as poorly designed as it sounds -- there
are operations that consume the most recent button press and can't be
repeated without another press. But you still have to keep
resubmitting the request until the user presses the button.)
--Andy
> (btw., Documentation/hid/hid-transport.txt is an overview of how HID
> transport layers work)
>
> Thanks
> David
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply
* [PATCH v3] HID: rmi: Scan the report descriptor to determine if the device is suitable for the hid-rmi driver
From: Andrew Duggan @ 2014-12-12 18:17 UTC (permalink / raw)
To: linux-input, linux-kernel; +Cc: Andrew Duggan, Jiri Kosina, Benjamin Tissoires
On composite HID devices there may be multiple HID devices on separate
interfaces, but hid-rmi should only bind to the touchpad. The previous version
simply checked that the interface protocol was set to mouse. Unfortuately, it
is not always the case that the touchpad has the mouse interface protocol set.
This patch takes a different approach and scans the report descriptor looking
for the Generic Desktop Pointer usage and the Vendor Specific Top Level
Collection needed by the hid-rmi driver to interface with the device.
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
Reviewed-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
---
Here is the v3 version with Benjamin's comments addressed. I also updated it to
apply to the version of hid-core.c in for-3.19/hid-rmi.
drivers/hid/hid-core.c | 22 +++++++++++++++++-----
include/linux/hid.h | 4 +++-
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index c3d0ac1..81665b4 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -698,6 +698,7 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
static void hid_scan_collection(struct hid_parser *parser, unsigned type)
{
struct hid_device *hid = parser->device;
+ int i;
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL)
@@ -707,6 +708,14 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 &&
hid->group == HID_GROUP_MULTITOUCH)
hid->group = HID_GROUP_GENERIC;
+
+ if ((parser->global.usage_page << 16) == HID_UP_GENDESK)
+ for (i = 0; i < parser->local.usage_index; i++)
+ if (parser->local.usage[i] == HID_GD_POINTER)
+ parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER;
+
+ if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR)
+ parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC;
}
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
@@ -792,11 +801,14 @@ static int hid_scan_report(struct hid_device *hid)
hid->group = HID_GROUP_WACOM;
break;
case USB_VENDOR_ID_SYNAPTICS:
- if ((hid->group == HID_GROUP_GENERIC) &&
- (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE))
- /* hid-rmi should only bind to the mouse interface of
- * composite USB devices */
- hid->group = HID_GROUP_RMI;
+ if (hid->group == HID_GROUP_GENERIC)
+ if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
+ && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
+ /*
+ * hid-rmi should take care of them,
+ * not hid-generic
+ */
+ hid->group = HID_GROUP_RMI;
break;
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 06c4607..efc7787 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
#define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4
-#define HID_SCAN_FLAG_MT_WIN_8 0x00000001
+#define HID_SCAN_FLAG_MT_WIN_8 BIT(0)
+#define HID_SCAN_FLAG_VENDOR_SPECIFIC BIT(1)
+#define HID_SCAN_FLAG_GD_POINTER BIT(2)
struct hid_parser {
struct hid_global global;
--
2.1.0
^ permalink raw reply related
* [PATCHv3 1/5] sunxi:dts-bindings:input:ps2 bindings for A10/A20 ps2.
From: VishnuPatekar @ 2014-12-12 18:25 UTC (permalink / raw)
To: linux-input, maxime.ripard, dmitry.torokhov, hdegoede
Cc: devicetree, linux-arm-kernel, linux-kernel, robh+dt, pawel.moll,
mark.rutland, ijc+devicetree, galak, linux, grant.likely, benh,
msalter, ralf, jdelvare, VishnuPatekar
In-Reply-To: <1418408748-9797-1-git-send-email-vishnupatekar0510@gmail.com>
1. dt bindings should use the compat string for the earliest version of the
hardware which has the relevant hardware block, unless there are differences,
the A10 and A20 ps2 controllers are identical, so for both sun4i-a10-ps2
should be used as compat string.
2. ps2 / serio bindings belong under Documentation/devicetree/bindings/serio
Signed-off-by: VishnuPatekar <vishnupatekar0510@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../bindings/serio/allwinner,sun4i-ps2.txt | 23 ++++++++++++++++++++
1 file changed, 23 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
diff --git a/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt b/Documentation/devicetree/bindings/serio/allwinner,sun4i-ps2.txt
new file mode 100644
index 0000000..0c30440
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/allwinner,sun4i-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 A10/A20 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 be as of the following:
+ - "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,sun4i-a10-ps2";
+ reg = <0x01c2a000 0x400>;
+ interrupts = <0 62 4>;
+ clocks = <&apb1_gates 6>;
+ status = "disabled";
+ };
--
1.7.9.5
^ 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