summaryrefslogtreecommitdiff
path: root/drivers/hid/hid-rmi.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-04-20 04:32:26 +0300
committerDave Airlie <airlied@redhat.com>2015-04-20 06:05:20 +0300
commit2c33ce009ca2389dbf0535d0672214d09738e35e (patch)
tree6186a6458c3c160385d794a23eaf07c786a9e61b /drivers/hid/hid-rmi.c
parentcec32a47010647e8b0603726ebb75b990a4057a4 (diff)
parent09d51602cf84a1264946711dd4ea0dddbac599a1 (diff)
downloadlinux-2c33ce009ca2389dbf0535d0672214d09738e35e.tar.xz
Merge Linus master into drm-next
The merge is clean, but the arm build fails afterwards, due to API changes in the regulator tree. I've included the patch into the merge to fix the build. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/hid/hid-rmi.c')
-rw-r--r--drivers/hid/hid-rmi.c177
1 files changed, 174 insertions, 3 deletions
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 49d4fe4f5987..368ffdf2c0a3 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -104,6 +104,7 @@ struct rmi_data {
unsigned long flags;
+ struct rmi_function f01;
struct rmi_function f11;
struct rmi_function f30;
@@ -124,6 +125,7 @@ struct rmi_data {
struct hid_device *hdev;
unsigned long device_flags;
+ unsigned long firmware_id;
};
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
@@ -272,6 +274,46 @@ static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf)
return rmi_read_block(hdev, addr, buf, 1);
}
+static int rmi_write_block(struct hid_device *hdev, u16 addr, void *buf,
+ const int len)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ int ret;
+
+ mutex_lock(&data->page_mutex);
+
+ if (RMI_PAGE(addr) != data->page) {
+ ret = rmi_set_page(hdev, RMI_PAGE(addr));
+ if (ret < 0)
+ goto exit;
+ }
+
+ data->writeReport[0] = RMI_WRITE_REPORT_ID;
+ data->writeReport[1] = len;
+ data->writeReport[2] = addr & 0xFF;
+ data->writeReport[3] = (addr >> 8) & 0xFF;
+ memcpy(&data->writeReport[4], buf, len);
+
+ ret = rmi_write_report(hdev, data->writeReport,
+ data->output_report_size);
+ if (ret < 0) {
+ dev_err(&hdev->dev,
+ "failed to write request output report (%d)\n",
+ ret);
+ goto exit;
+ }
+ ret = 0;
+
+exit:
+ mutex_unlock(&data->page_mutex);
+ return ret;
+}
+
+static inline int rmi_write(struct hid_device *hdev, u16 addr, void *buf)
+{
+ return rmi_write_block(hdev, addr, buf, 1);
+}
+
static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
u8 finger_state, u8 *touch_data)
{
@@ -532,6 +574,9 @@ static void rmi_register_function(struct rmi_data *data,
u16 page_base = page << 8;
switch (pdt_entry->function_number) {
+ case 0x01:
+ f = &data->f01;
+ break;
case 0x11:
f = &data->f11;
break;
@@ -604,6 +649,92 @@ error_exit:
return retval;
}
+#define RMI_DEVICE_F01_BASIC_QUERY_LEN 11
+
+static int rmi_populate_f01(struct hid_device *hdev)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ u8 basic_queries[RMI_DEVICE_F01_BASIC_QUERY_LEN];
+ u8 info[3];
+ int ret;
+ bool has_query42;
+ bool has_lts;
+ bool has_sensor_id;
+ bool has_ds4_queries = false;
+ bool has_build_id_query = false;
+ bool has_package_id_query = false;
+ u16 query_offset = data->f01.query_base_addr;
+ u16 prod_info_addr;
+ u8 ds4_query_len;
+
+ ret = rmi_read_block(hdev, query_offset, basic_queries,
+ RMI_DEVICE_F01_BASIC_QUERY_LEN);
+ if (ret) {
+ hid_err(hdev, "Can not read basic queries from Function 0x1.\n");
+ return ret;
+ }
+
+ has_lts = !!(basic_queries[0] & BIT(2));
+ has_sensor_id = !!(basic_queries[1] & BIT(3));
+ has_query42 = !!(basic_queries[1] & BIT(7));
+
+ query_offset += 11;
+ prod_info_addr = query_offset + 6;
+ query_offset += 10;
+
+ if (has_lts)
+ query_offset += 20;
+
+ if (has_sensor_id)
+ query_offset++;
+
+ if (has_query42) {
+ ret = rmi_read(hdev, query_offset, info);
+ if (ret) {
+ hid_err(hdev, "Can not read query42.\n");
+ return ret;
+ }
+ has_ds4_queries = !!(info[0] & BIT(0));
+ query_offset++;
+ }
+
+ if (has_ds4_queries) {
+ ret = rmi_read(hdev, query_offset, &ds4_query_len);
+ if (ret) {
+ hid_err(hdev, "Can not read DS4 Query length.\n");
+ return ret;
+ }
+ query_offset++;
+
+ if (ds4_query_len > 0) {
+ ret = rmi_read(hdev, query_offset, info);
+ if (ret) {
+ hid_err(hdev, "Can not read DS4 query.\n");
+ return ret;
+ }
+
+ has_package_id_query = !!(info[0] & BIT(0));
+ has_build_id_query = !!(info[0] & BIT(1));
+ }
+ }
+
+ if (has_package_id_query)
+ prod_info_addr++;
+
+ if (has_build_id_query) {
+ ret = rmi_read_block(hdev, prod_info_addr, info, 3);
+ if (ret) {
+ hid_err(hdev, "Can not read product info.\n");
+ return ret;
+ }
+
+ data->firmware_id = info[1] << 8 | info[0];
+ data->firmware_id += info[2] * 65536;
+ }
+
+ return 0;
+}
+
static int rmi_populate_f11(struct hid_device *hdev)
{
struct rmi_data *data = hid_get_drvdata(hdev);
@@ -620,6 +751,8 @@ static int rmi_populate_f11(struct hid_device *hdev)
bool has_gestures;
bool has_rel;
bool has_data40 = false;
+ bool has_dribble = false;
+ bool has_palm_detect = false;
unsigned x_size, y_size;
u16 query_offset;
@@ -661,6 +794,14 @@ static int rmi_populate_f11(struct hid_device *hdev)
has_rel = !!(buf[0] & BIT(3));
has_gestures = !!(buf[0] & BIT(5));
+ ret = rmi_read(hdev, data->f11.query_base_addr + 5, buf);
+ if (ret) {
+ hid_err(hdev, "can not get absolute data sources: %d.\n", ret);
+ return ret;
+ }
+
+ has_dribble = !!(buf[0] & BIT(4));
+
/*
* At least 4 queries are guaranteed to be present in F11
* +1 for query 5 which is present since absolute events are
@@ -680,6 +821,7 @@ static int rmi_populate_f11(struct hid_device *hdev)
ret);
return ret;
}
+ has_palm_detect = !!(buf[0] & BIT(0));
has_query10 = !!(buf[0] & BIT(2));
query_offset += 2; /* query 7 and 8 are present */
@@ -766,17 +908,38 @@ static int rmi_populate_f11(struct hid_device *hdev)
* retrieve the ctrl registers
* the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
* and there is no way to know if the first 20 bytes are here or not.
- * We use only the first 10 bytes, so get only them.
+ * We use only the first 12 bytes, so get only them.
*/
- ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 10);
+ ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12);
if (ret) {
- hid_err(hdev, "can not read ctrl block of size 10: %d.\n", ret);
+ hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret);
return ret;
}
data->max_x = buf[6] | (buf[7] << 8);
data->max_y = buf[8] | (buf[9] << 8);
+ if (has_dribble) {
+ buf[0] = buf[0] & ~BIT(6);
+ ret = rmi_write(hdev, data->f11.control_base_addr, buf);
+ if (ret) {
+ hid_err(hdev, "can not write to control reg 0: %d.\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (has_palm_detect) {
+ buf[11] = buf[11] & ~BIT(0);
+ ret = rmi_write(hdev, data->f11.control_base_addr + 11,
+ &buf[11]);
+ if (ret) {
+ hid_err(hdev, "can not write to control reg 11: %d.\n",
+ ret);
+ return ret;
+ }
+ }
+
return 0;
}
@@ -858,6 +1021,12 @@ static int rmi_populate(struct hid_device *hdev)
return ret;
}
+ ret = rmi_populate_f01(hdev);
+ if (ret) {
+ hid_err(hdev, "Error while initializing F01 (%d).\n", ret);
+ return ret;
+ }
+
ret = rmi_populate_f11(hdev);
if (ret) {
hid_err(hdev, "Error while initializing F11 (%d).\n", ret);
@@ -907,6 +1076,8 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret)
goto exit;
+ hid_info(hdev, "firmware id: %ld\n", data->firmware_id);
+
__set_bit(EV_ABS, input->evbit);
input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0);