12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
29fb6bf02SBenjamin Tissoires /*
39fb6bf02SBenjamin Tissoires * Copyright (c) 2013 Andrew Duggan <aduggan@synaptics.com>
49fb6bf02SBenjamin Tissoires * Copyright (c) 2013 Synaptics Incorporated
59fb6bf02SBenjamin Tissoires * Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@gmail.com>
69fb6bf02SBenjamin Tissoires * Copyright (c) 2014 Red Hat, Inc
79fb6bf02SBenjamin Tissoires */
89fb6bf02SBenjamin Tissoires
99fb6bf02SBenjamin Tissoires #include <linux/kernel.h>
109fb6bf02SBenjamin Tissoires #include <linux/hid.h>
119fb6bf02SBenjamin Tissoires #include <linux/input.h>
129fb6bf02SBenjamin Tissoires #include <linux/input/mt.h>
130b2c7a89SAndrew Duggan #include <linux/irq.h>
140b2c7a89SAndrew Duggan #include <linux/irqdomain.h>
159fb6bf02SBenjamin Tissoires #include <linux/module.h>
169fb6bf02SBenjamin Tissoires #include <linux/pm.h>
179fb6bf02SBenjamin Tissoires #include <linux/slab.h>
189fb6bf02SBenjamin Tissoires #include <linux/wait.h>
199fb6bf02SBenjamin Tissoires #include <linux/sched.h>
200b2c7a89SAndrew Duggan #include <linux/rmi.h>
219fb6bf02SBenjamin Tissoires #include "hid-ids.h"
229fb6bf02SBenjamin Tissoires
239fb6bf02SBenjamin Tissoires #define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */
249fb6bf02SBenjamin Tissoires #define RMI_WRITE_REPORT_ID 0x09 /* Output Report */
259fb6bf02SBenjamin Tissoires #define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */
269fb6bf02SBenjamin Tissoires #define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */
279fb6bf02SBenjamin Tissoires #define RMI_ATTN_REPORT_ID 0x0c /* Input Report */
289fb6bf02SBenjamin Tissoires #define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */
299fb6bf02SBenjamin Tissoires
309fb6bf02SBenjamin Tissoires /* flags */
31af43c408SDan Carpenter #define RMI_READ_REQUEST_PENDING 0
32af43c408SDan Carpenter #define RMI_READ_DATA_PENDING 1
33af43c408SDan Carpenter #define RMI_STARTED 2
349fb6bf02SBenjamin Tissoires
352f43de60SAndrew Duggan /* device flags */
362f43de60SAndrew Duggan #define RMI_DEVICE BIT(0)
3779364d87SAndrew Duggan #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1)
3810235380STobias Auerochs #define RMI_DEVICE_OUTPUT_SET_REPORT BIT(2)
392f43de60SAndrew Duggan
407035f3a4SAndrew Duggan /*
417035f3a4SAndrew Duggan * retrieve the ctrl registers
427035f3a4SAndrew Duggan * the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
437035f3a4SAndrew Duggan * and there is no way to know if the first 20 bytes are here or not.
447035f3a4SAndrew Duggan * We use only the first 12 bytes, so get only them.
457035f3a4SAndrew Duggan */
467035f3a4SAndrew Duggan #define RMI_F11_CTRL_REG_COUNT 12
477035f3a4SAndrew Duggan
489fb6bf02SBenjamin Tissoires enum rmi_mode_type {
499fb6bf02SBenjamin Tissoires RMI_MODE_OFF = 0,
509fb6bf02SBenjamin Tissoires RMI_MODE_ATTN_REPORTS = 1,
519fb6bf02SBenjamin Tissoires RMI_MODE_NO_PACKED_ATTN_REPORTS = 2,
529fb6bf02SBenjamin Tissoires };
539fb6bf02SBenjamin Tissoires
549fb6bf02SBenjamin Tissoires /**
559fb6bf02SBenjamin Tissoires * struct rmi_data - stores information for hid communication
569fb6bf02SBenjamin Tissoires *
579fb6bf02SBenjamin Tissoires * @page_mutex: Locks current page to avoid changing pages in unexpected ways.
589fb6bf02SBenjamin Tissoires * @page: Keeps track of the current virtual page
590b2c7a89SAndrew Duggan * @xport: transport device to be registered with the RMI4 core.
609fb6bf02SBenjamin Tissoires *
619fb6bf02SBenjamin Tissoires * @wait: Used for waiting for read data
629fb6bf02SBenjamin Tissoires *
639fb6bf02SBenjamin Tissoires * @writeReport: output buffer when writing RMI registers
649fb6bf02SBenjamin Tissoires * @readReport: input buffer when reading RMI registers
659fb6bf02SBenjamin Tissoires *
669fb6bf02SBenjamin Tissoires * @input_report_size: size of an input report (advertised by HID)
679fb6bf02SBenjamin Tissoires * @output_report_size: size of an output report (advertised by HID)
689fb6bf02SBenjamin Tissoires *
699fb6bf02SBenjamin Tissoires * @flags: flags for the current device (started, reading, etc...)
709fb6bf02SBenjamin Tissoires *
719fb6bf02SBenjamin Tissoires * @reset_work: worker which will be called in case of a mouse report
729fb6bf02SBenjamin Tissoires * @hdev: pointer to the struct hid_device
730b2c7a89SAndrew Duggan *
740b2c7a89SAndrew Duggan * @device_flags: flags which describe the device
750b2c7a89SAndrew Duggan *
760b2c7a89SAndrew Duggan * @domain: the IRQ domain allocated for this RMI4 device
770b2c7a89SAndrew Duggan * @rmi_irq: the irq that will be used to generate events to rmi-core
789fb6bf02SBenjamin Tissoires */
799fb6bf02SBenjamin Tissoires struct rmi_data {
809fb6bf02SBenjamin Tissoires struct mutex page_mutex;
819fb6bf02SBenjamin Tissoires int page;
820b2c7a89SAndrew Duggan struct rmi_transport_dev xport;
839fb6bf02SBenjamin Tissoires
849fb6bf02SBenjamin Tissoires wait_queue_head_t wait;
859fb6bf02SBenjamin Tissoires
869fb6bf02SBenjamin Tissoires u8 *writeReport;
879fb6bf02SBenjamin Tissoires u8 *readReport;
889fb6bf02SBenjamin Tissoires
893064a03bSAaron Ma u32 input_report_size;
903064a03bSAaron Ma u32 output_report_size;
919fb6bf02SBenjamin Tissoires
929fb6bf02SBenjamin Tissoires unsigned long flags;
939fb6bf02SBenjamin Tissoires
949fb6bf02SBenjamin Tissoires struct work_struct reset_work;
959fb6bf02SBenjamin Tissoires struct hid_device *hdev;
962f43de60SAndrew Duggan
972f43de60SAndrew Duggan unsigned long device_flags;
9809256360SAndrew Duggan
990b2c7a89SAndrew Duggan struct irq_domain *domain;
1000b2c7a89SAndrew Duggan int rmi_irq;
1019fb6bf02SBenjamin Tissoires };
1029fb6bf02SBenjamin Tissoires
1039fb6bf02SBenjamin Tissoires #define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
1049fb6bf02SBenjamin Tissoires
1059fb6bf02SBenjamin Tissoires static int rmi_write_report(struct hid_device *hdev, u8 *report, int len);
1069fb6bf02SBenjamin Tissoires
1079fb6bf02SBenjamin Tissoires /**
1089fb6bf02SBenjamin Tissoires * rmi_set_page - Set RMI page
1099fb6bf02SBenjamin Tissoires * @hdev: The pointer to the hid_device struct
1109fb6bf02SBenjamin Tissoires * @page: The new page address.
1119fb6bf02SBenjamin Tissoires *
1129fb6bf02SBenjamin Tissoires * RMI devices have 16-bit addressing, but some of the physical
1139fb6bf02SBenjamin Tissoires * implementations (like SMBus) only have 8-bit addressing. So RMI implements
1149fb6bf02SBenjamin Tissoires * a page address at 0xff of every page so we can reliable page addresses
1159fb6bf02SBenjamin Tissoires * every 256 registers.
1169fb6bf02SBenjamin Tissoires *
1179fb6bf02SBenjamin Tissoires * The page_mutex lock must be held when this function is entered.
1189fb6bf02SBenjamin Tissoires *
1199fb6bf02SBenjamin Tissoires * Returns zero on success, non-zero on failure.
1209fb6bf02SBenjamin Tissoires */
rmi_set_page(struct hid_device * hdev,u8 page)1219fb6bf02SBenjamin Tissoires static int rmi_set_page(struct hid_device *hdev, u8 page)
1229fb6bf02SBenjamin Tissoires {
1239fb6bf02SBenjamin Tissoires struct rmi_data *data = hid_get_drvdata(hdev);
1249fb6bf02SBenjamin Tissoires int retval;
1259fb6bf02SBenjamin Tissoires
1269fb6bf02SBenjamin Tissoires data->writeReport[0] = RMI_WRITE_REPORT_ID;
1279fb6bf02SBenjamin Tissoires data->writeReport[1] = 1;
1289fb6bf02SBenjamin Tissoires data->writeReport[2] = 0xFF;
1299fb6bf02SBenjamin Tissoires data->writeReport[4] = page;
1309fb6bf02SBenjamin Tissoires
1319fb6bf02SBenjamin Tissoires retval = rmi_write_report(hdev, data->writeReport,
1329fb6bf02SBenjamin Tissoires data->output_report_size);
1339fb6bf02SBenjamin Tissoires if (retval != data->output_report_size) {
1349fb6bf02SBenjamin Tissoires dev_err(&hdev->dev,
1359fb6bf02SBenjamin Tissoires "%s: set page failed: %d.", __func__, retval);
1369fb6bf02SBenjamin Tissoires return retval;
1379fb6bf02SBenjamin Tissoires }
1389fb6bf02SBenjamin Tissoires
1399fb6bf02SBenjamin Tissoires data->page = page;
1409fb6bf02SBenjamin Tissoires return 0;
1419fb6bf02SBenjamin Tissoires }
1429fb6bf02SBenjamin Tissoires
rmi_set_mode(struct hid_device * hdev,u8 mode)1439fb6bf02SBenjamin Tissoires static int rmi_set_mode(struct hid_device *hdev, u8 mode)
1449fb6bf02SBenjamin Tissoires {
1459fb6bf02SBenjamin Tissoires int ret;
1466dab07dfSBenjamin Tissoires const u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
1476dab07dfSBenjamin Tissoires u8 *buf;
1489fb6bf02SBenjamin Tissoires
1496dab07dfSBenjamin Tissoires buf = kmemdup(txbuf, sizeof(txbuf), GFP_KERNEL);
1506dab07dfSBenjamin Tissoires if (!buf)
1516dab07dfSBenjamin Tissoires return -ENOMEM;
1526dab07dfSBenjamin Tissoires
1536dab07dfSBenjamin Tissoires ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, buf,
1549fb6bf02SBenjamin Tissoires sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
1556dab07dfSBenjamin Tissoires kfree(buf);
1569fb6bf02SBenjamin Tissoires if (ret < 0) {
1579fb6bf02SBenjamin Tissoires dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode,
1589fb6bf02SBenjamin Tissoires ret);
1599fb6bf02SBenjamin Tissoires return ret;
1609fb6bf02SBenjamin Tissoires }
1619fb6bf02SBenjamin Tissoires
1629fb6bf02SBenjamin Tissoires return 0;
1639fb6bf02SBenjamin Tissoires }
1649fb6bf02SBenjamin Tissoires
rmi_write_report(struct hid_device * hdev,u8 * report,int len)1659fb6bf02SBenjamin Tissoires static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
1669fb6bf02SBenjamin Tissoires {
16710235380STobias Auerochs struct rmi_data *data = hid_get_drvdata(hdev);
1689fb6bf02SBenjamin Tissoires int ret;
1699fb6bf02SBenjamin Tissoires
17010235380STobias Auerochs if (data->device_flags & RMI_DEVICE_OUTPUT_SET_REPORT) {
17110235380STobias Auerochs /*
17210235380STobias Auerochs * Talk to device by using SET_REPORT requests instead.
17310235380STobias Auerochs */
17410235380STobias Auerochs ret = hid_hw_raw_request(hdev, report[0], report,
17510235380STobias Auerochs len, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
17610235380STobias Auerochs } else {
1779fb6bf02SBenjamin Tissoires ret = hid_hw_output_report(hdev, (void *)report, len);
17810235380STobias Auerochs }
17910235380STobias Auerochs
1809fb6bf02SBenjamin Tissoires if (ret < 0) {
1819fb6bf02SBenjamin Tissoires dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
1829fb6bf02SBenjamin Tissoires return ret;
1839fb6bf02SBenjamin Tissoires }
1849fb6bf02SBenjamin Tissoires
1859fb6bf02SBenjamin Tissoires return ret;
1869fb6bf02SBenjamin Tissoires }
1879fb6bf02SBenjamin Tissoires
rmi_hid_read_block(struct rmi_transport_dev * xport,u16 addr,void * buf,size_t len)1880b2c7a89SAndrew Duggan static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr,
1890b2c7a89SAndrew Duggan void *buf, size_t len)
1909fb6bf02SBenjamin Tissoires {
1910b2c7a89SAndrew Duggan struct rmi_data *data = container_of(xport, struct rmi_data, xport);
1920b2c7a89SAndrew Duggan struct hid_device *hdev = data->hdev;
1939fb6bf02SBenjamin Tissoires int ret;
1949fb6bf02SBenjamin Tissoires int bytes_read;
1959fb6bf02SBenjamin Tissoires int bytes_needed;
1969fb6bf02SBenjamin Tissoires int retries;
1979fb6bf02SBenjamin Tissoires int read_input_count;
1989fb6bf02SBenjamin Tissoires
1999fb6bf02SBenjamin Tissoires mutex_lock(&data->page_mutex);
2009fb6bf02SBenjamin Tissoires
2019fb6bf02SBenjamin Tissoires if (RMI_PAGE(addr) != data->page) {
2029fb6bf02SBenjamin Tissoires ret = rmi_set_page(hdev, RMI_PAGE(addr));
2039fb6bf02SBenjamin Tissoires if (ret < 0)
2049fb6bf02SBenjamin Tissoires goto exit;
2059fb6bf02SBenjamin Tissoires }
2069fb6bf02SBenjamin Tissoires
2079fb6bf02SBenjamin Tissoires for (retries = 5; retries > 0; retries--) {
2089fb6bf02SBenjamin Tissoires data->writeReport[0] = RMI_READ_ADDR_REPORT_ID;
2099fb6bf02SBenjamin Tissoires data->writeReport[1] = 0; /* old 1 byte read count */
2109fb6bf02SBenjamin Tissoires data->writeReport[2] = addr & 0xFF;
2119fb6bf02SBenjamin Tissoires data->writeReport[3] = (addr >> 8) & 0xFF;
2129fb6bf02SBenjamin Tissoires data->writeReport[4] = len & 0xFF;
2139fb6bf02SBenjamin Tissoires data->writeReport[5] = (len >> 8) & 0xFF;
2149fb6bf02SBenjamin Tissoires
2159fb6bf02SBenjamin Tissoires set_bit(RMI_READ_REQUEST_PENDING, &data->flags);
2169fb6bf02SBenjamin Tissoires
2179fb6bf02SBenjamin Tissoires ret = rmi_write_report(hdev, data->writeReport,
2189fb6bf02SBenjamin Tissoires data->output_report_size);
2199fb6bf02SBenjamin Tissoires if (ret != data->output_report_size) {
2209fb6bf02SBenjamin Tissoires dev_err(&hdev->dev,
2219fb6bf02SBenjamin Tissoires "failed to write request output report (%d)\n",
2229fb6bf02SBenjamin Tissoires ret);
2239fb6bf02SBenjamin Tissoires goto exit;
2249fb6bf02SBenjamin Tissoires }
2259fb6bf02SBenjamin Tissoires
2269fb6bf02SBenjamin Tissoires bytes_read = 0;
2279fb6bf02SBenjamin Tissoires bytes_needed = len;
2289fb6bf02SBenjamin Tissoires while (bytes_read < len) {
2299fb6bf02SBenjamin Tissoires if (!wait_event_timeout(data->wait,
2309fb6bf02SBenjamin Tissoires test_bit(RMI_READ_DATA_PENDING, &data->flags),
2319fb6bf02SBenjamin Tissoires msecs_to_jiffies(1000))) {
2329fb6bf02SBenjamin Tissoires hid_warn(hdev, "%s: timeout elapsed\n",
2339fb6bf02SBenjamin Tissoires __func__);
2349fb6bf02SBenjamin Tissoires ret = -EAGAIN;
2359fb6bf02SBenjamin Tissoires break;
2369fb6bf02SBenjamin Tissoires }
2379fb6bf02SBenjamin Tissoires
2389fb6bf02SBenjamin Tissoires read_input_count = data->readReport[1];
2399fb6bf02SBenjamin Tissoires memcpy(buf + bytes_read, &data->readReport[2],
240486da113SJiangshan Yi min(read_input_count, bytes_needed));
2419fb6bf02SBenjamin Tissoires
2429fb6bf02SBenjamin Tissoires bytes_read += read_input_count;
2439fb6bf02SBenjamin Tissoires bytes_needed -= read_input_count;
2449fb6bf02SBenjamin Tissoires clear_bit(RMI_READ_DATA_PENDING, &data->flags);
2459fb6bf02SBenjamin Tissoires }
2469fb6bf02SBenjamin Tissoires
2479fb6bf02SBenjamin Tissoires if (ret >= 0) {
2489fb6bf02SBenjamin Tissoires ret = 0;
2499fb6bf02SBenjamin Tissoires break;
2509fb6bf02SBenjamin Tissoires }
2519fb6bf02SBenjamin Tissoires }
2529fb6bf02SBenjamin Tissoires
2539fb6bf02SBenjamin Tissoires exit:
2549fb6bf02SBenjamin Tissoires clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
2559fb6bf02SBenjamin Tissoires mutex_unlock(&data->page_mutex);
2569fb6bf02SBenjamin Tissoires return ret;
2579fb6bf02SBenjamin Tissoires }
2589fb6bf02SBenjamin Tissoires
rmi_hid_write_block(struct rmi_transport_dev * xport,u16 addr,const void * buf,size_t len)2590b2c7a89SAndrew Duggan static int rmi_hid_write_block(struct rmi_transport_dev *xport, u16 addr,
2600b2c7a89SAndrew Duggan const void *buf, size_t len)
2619fb6bf02SBenjamin Tissoires {
2620b2c7a89SAndrew Duggan struct rmi_data *data = container_of(xport, struct rmi_data, xport);
2630b2c7a89SAndrew Duggan struct hid_device *hdev = data->hdev;
264dd8df284SAndrew Duggan int ret;
265dd8df284SAndrew Duggan
266dd8df284SAndrew Duggan mutex_lock(&data->page_mutex);
267dd8df284SAndrew Duggan
268dd8df284SAndrew Duggan if (RMI_PAGE(addr) != data->page) {
269dd8df284SAndrew Duggan ret = rmi_set_page(hdev, RMI_PAGE(addr));
270dd8df284SAndrew Duggan if (ret < 0)
271dd8df284SAndrew Duggan goto exit;
272dd8df284SAndrew Duggan }
273dd8df284SAndrew Duggan
274dd8df284SAndrew Duggan data->writeReport[0] = RMI_WRITE_REPORT_ID;
275dd8df284SAndrew Duggan data->writeReport[1] = len;
276dd8df284SAndrew Duggan data->writeReport[2] = addr & 0xFF;
277dd8df284SAndrew Duggan data->writeReport[3] = (addr >> 8) & 0xFF;
278dd8df284SAndrew Duggan memcpy(&data->writeReport[4], buf, len);
279dd8df284SAndrew Duggan
280dd8df284SAndrew Duggan ret = rmi_write_report(hdev, data->writeReport,
281dd8df284SAndrew Duggan data->output_report_size);
282dd8df284SAndrew Duggan if (ret < 0) {
283dd8df284SAndrew Duggan dev_err(&hdev->dev,
284dd8df284SAndrew Duggan "failed to write request output report (%d)\n",
285dd8df284SAndrew Duggan ret);
286dd8df284SAndrew Duggan goto exit;
287dd8df284SAndrew Duggan }
288dd8df284SAndrew Duggan ret = 0;
289dd8df284SAndrew Duggan
290dd8df284SAndrew Duggan exit:
291dd8df284SAndrew Duggan mutex_unlock(&data->page_mutex);
292dd8df284SAndrew Duggan return ret;
293dd8df284SAndrew Duggan }
294dd8df284SAndrew Duggan
rmi_reset_attn_mode(struct hid_device * hdev)2959a98b338SAndrew Duggan static int rmi_reset_attn_mode(struct hid_device *hdev)
2969a98b338SAndrew Duggan {
2979a98b338SAndrew Duggan struct rmi_data *data = hid_get_drvdata(hdev);
2980b2c7a89SAndrew Duggan struct rmi_device *rmi_dev = data->xport.rmi_dev;
2999a98b338SAndrew Duggan int ret;
3009a98b338SAndrew Duggan
3019a98b338SAndrew Duggan ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
3029a98b338SAndrew Duggan if (ret)
3039a98b338SAndrew Duggan return ret;
3049a98b338SAndrew Duggan
3050b2c7a89SAndrew Duggan if (test_bit(RMI_STARTED, &data->flags))
3060b2c7a89SAndrew Duggan ret = rmi_dev->driver->reset_handler(rmi_dev);
3079a98b338SAndrew Duggan
3080b2c7a89SAndrew Duggan return ret;
3099a98b338SAndrew Duggan }
3109a98b338SAndrew Duggan
rmi_reset_work(struct work_struct * work)3119fb6bf02SBenjamin Tissoires static void rmi_reset_work(struct work_struct *work)
3129fb6bf02SBenjamin Tissoires {
3139fb6bf02SBenjamin Tissoires struct rmi_data *hdata = container_of(work, struct rmi_data,
3149fb6bf02SBenjamin Tissoires reset_work);
3159fb6bf02SBenjamin Tissoires
3169fb6bf02SBenjamin Tissoires /* switch the device to RMI if we receive a generic mouse report */
3179a98b338SAndrew Duggan rmi_reset_attn_mode(hdata->hdev);
3189fb6bf02SBenjamin Tissoires }
3199fb6bf02SBenjamin Tissoires
rmi_input_event(struct hid_device * hdev,u8 * data,int size)3209fb6bf02SBenjamin Tissoires static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
3219fb6bf02SBenjamin Tissoires {
3229fb6bf02SBenjamin Tissoires struct rmi_data *hdata = hid_get_drvdata(hdev);
3230b2c7a89SAndrew Duggan struct rmi_device *rmi_dev = hdata->xport.rmi_dev;
3240b2c7a89SAndrew Duggan unsigned long flags;
3259fb6bf02SBenjamin Tissoires
3269fb6bf02SBenjamin Tissoires if (!(test_bit(RMI_STARTED, &hdata->flags)))
3279fb6bf02SBenjamin Tissoires return 0;
3289fb6bf02SBenjamin Tissoires
329*9984fbf5SDmitry Torokhov pm_wakeup_event(hdev->dev.parent, 0);
330*9984fbf5SDmitry Torokhov
3310b2c7a89SAndrew Duggan local_irq_save(flags);
3329fb6bf02SBenjamin Tissoires
3330b2c7a89SAndrew Duggan rmi_set_attn_data(rmi_dev, data[1], &data[2], size - 2);
3349fb6bf02SBenjamin Tissoires
3350b2c7a89SAndrew Duggan generic_handle_irq(hdata->rmi_irq);
3360b2c7a89SAndrew Duggan
3370b2c7a89SAndrew Duggan local_irq_restore(flags);
3389fb6bf02SBenjamin Tissoires
3399fb6bf02SBenjamin Tissoires return 1;
3409fb6bf02SBenjamin Tissoires }
3419fb6bf02SBenjamin Tissoires
rmi_read_data_event(struct hid_device * hdev,u8 * data,int size)3429fb6bf02SBenjamin Tissoires static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
3439fb6bf02SBenjamin Tissoires {
3449fb6bf02SBenjamin Tissoires struct rmi_data *hdata = hid_get_drvdata(hdev);
3459fb6bf02SBenjamin Tissoires
3469fb6bf02SBenjamin Tissoires if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
34701a5f8a4SAndrew Duggan hid_dbg(hdev, "no read request pending\n");
3489fb6bf02SBenjamin Tissoires return 0;
3499fb6bf02SBenjamin Tissoires }
3509fb6bf02SBenjamin Tissoires
351486da113SJiangshan Yi memcpy(hdata->readReport, data, min((u32)size, hdata->input_report_size));
3529fb6bf02SBenjamin Tissoires set_bit(RMI_READ_DATA_PENDING, &hdata->flags);
3539fb6bf02SBenjamin Tissoires wake_up(&hdata->wait);
3549fb6bf02SBenjamin Tissoires
3559fb6bf02SBenjamin Tissoires return 1;
3569fb6bf02SBenjamin Tissoires }
3579fb6bf02SBenjamin Tissoires
rmi_check_sanity(struct hid_device * hdev,u8 * data,int size)3585b65c2a0SBenjamin Tissoires static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size)
3595b65c2a0SBenjamin Tissoires {
3605b65c2a0SBenjamin Tissoires int valid_size = size;
3615b65c2a0SBenjamin Tissoires /*
3625b65c2a0SBenjamin Tissoires * On the Dell XPS 13 9333, the bus sometimes get confused and fills
3635b65c2a0SBenjamin Tissoires * the report with a sentinel value "ff". Synaptics told us that such
3645b65c2a0SBenjamin Tissoires * behavior does not comes from the touchpad itself, so we filter out
3655b65c2a0SBenjamin Tissoires * such reports here.
3665b65c2a0SBenjamin Tissoires */
3675b65c2a0SBenjamin Tissoires
3685b65c2a0SBenjamin Tissoires while ((data[valid_size - 1] == 0xff) && valid_size > 0)
3695b65c2a0SBenjamin Tissoires valid_size--;
3705b65c2a0SBenjamin Tissoires
3715b65c2a0SBenjamin Tissoires return valid_size;
3725b65c2a0SBenjamin Tissoires }
3735b65c2a0SBenjamin Tissoires
rmi_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)3749fb6bf02SBenjamin Tissoires static int rmi_raw_event(struct hid_device *hdev,
3759fb6bf02SBenjamin Tissoires struct hid_report *report, u8 *data, int size)
3769fb6bf02SBenjamin Tissoires {
377ef14a4bfSAndrew Duggan struct rmi_data *hdata = hid_get_drvdata(hdev);
378ef14a4bfSAndrew Duggan
379ef14a4bfSAndrew Duggan if (!(hdata->device_flags & RMI_DEVICE))
380ef14a4bfSAndrew Duggan return 0;
381ef14a4bfSAndrew Duggan
3825b65c2a0SBenjamin Tissoires size = rmi_check_sanity(hdev, data, size);
3835b65c2a0SBenjamin Tissoires if (size < 2)
3845b65c2a0SBenjamin Tissoires return 0;
3855b65c2a0SBenjamin Tissoires
3869fb6bf02SBenjamin Tissoires switch (data[0]) {
3879fb6bf02SBenjamin Tissoires case RMI_READ_DATA_REPORT_ID:
3889fb6bf02SBenjamin Tissoires return rmi_read_data_event(hdev, data, size);
3899fb6bf02SBenjamin Tissoires case RMI_ATTN_REPORT_ID:
3909fb6bf02SBenjamin Tissoires return rmi_input_event(hdev, data, size);
3912f43de60SAndrew Duggan default:
3922f43de60SAndrew Duggan return 1;
3932f43de60SAndrew Duggan }
3942f43de60SAndrew Duggan
3952f43de60SAndrew Duggan return 0;
3962f43de60SAndrew Duggan }
3972f43de60SAndrew Duggan
rmi_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)3982f43de60SAndrew Duggan static int rmi_event(struct hid_device *hdev, struct hid_field *field,
3992f43de60SAndrew Duggan struct hid_usage *usage, __s32 value)
4002f43de60SAndrew Duggan {
4012f43de60SAndrew Duggan struct rmi_data *data = hid_get_drvdata(hdev);
4022f43de60SAndrew Duggan
4032f43de60SAndrew Duggan if ((data->device_flags & RMI_DEVICE) &&
4042f43de60SAndrew Duggan (field->application == HID_GD_POINTER ||
4052f43de60SAndrew Duggan field->application == HID_GD_MOUSE)) {
40679364d87SAndrew Duggan if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) {
40779364d87SAndrew Duggan if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
40879364d87SAndrew Duggan return 0;
40979364d87SAndrew Duggan
41079364d87SAndrew Duggan if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y)
41179364d87SAndrew Duggan && !value)
41279364d87SAndrew Duggan return 1;
41379364d87SAndrew Duggan }
41479364d87SAndrew Duggan
4150b2c7a89SAndrew Duggan schedule_work(&data->reset_work);
4162f43de60SAndrew Duggan return 1;
4179fb6bf02SBenjamin Tissoires }
4189fb6bf02SBenjamin Tissoires
4199fb6bf02SBenjamin Tissoires return 0;
4209fb6bf02SBenjamin Tissoires }
4219fb6bf02SBenjamin Tissoires
rmi_report(struct hid_device * hid,struct hid_report * report)422c94ba060SBenjamin Tissoires static void rmi_report(struct hid_device *hid, struct hid_report *report)
423c94ba060SBenjamin Tissoires {
424c94ba060SBenjamin Tissoires struct hid_field *field = report->field[0];
425c94ba060SBenjamin Tissoires
426c94ba060SBenjamin Tissoires if (!(hid->claimed & HID_CLAIMED_INPUT))
427c94ba060SBenjamin Tissoires return;
428c94ba060SBenjamin Tissoires
429c94ba060SBenjamin Tissoires switch (report->id) {
430c94ba060SBenjamin Tissoires case RMI_READ_DATA_REPORT_ID:
431c94ba060SBenjamin Tissoires case RMI_ATTN_REPORT_ID:
432c94ba060SBenjamin Tissoires return;
433c94ba060SBenjamin Tissoires }
434c94ba060SBenjamin Tissoires
435c94ba060SBenjamin Tissoires if (field && field->hidinput && field->hidinput->input)
436c94ba060SBenjamin Tissoires input_sync(field->hidinput->input);
437c94ba060SBenjamin Tissoires }
438c94ba060SBenjamin Tissoires
439a278e268SGeert Uytterhoeven #ifdef CONFIG_PM
rmi_suspend(struct hid_device * hdev,pm_message_t message)4400b2c7a89SAndrew Duggan static int rmi_suspend(struct hid_device *hdev, pm_message_t message)
44109256360SAndrew Duggan {
44209256360SAndrew Duggan struct rmi_data *data = hid_get_drvdata(hdev);
4430b2c7a89SAndrew Duggan struct rmi_device *rmi_dev = data->xport.rmi_dev;
44409256360SAndrew Duggan int ret;
44509256360SAndrew Duggan
4460b2c7a89SAndrew Duggan if (!(data->device_flags & RMI_DEVICE))
4470b2c7a89SAndrew Duggan return 0;
44809256360SAndrew Duggan
4490b2c7a89SAndrew Duggan ret = rmi_driver_suspend(rmi_dev, false);
45009256360SAndrew Duggan if (ret) {
4510b2c7a89SAndrew Duggan hid_warn(hdev, "Failed to suspend device: %d\n", ret);
45209256360SAndrew Duggan return ret;
45309256360SAndrew Duggan }
45409256360SAndrew Duggan
45509256360SAndrew Duggan return 0;
45609256360SAndrew Duggan }
45709256360SAndrew Duggan
rmi_post_resume(struct hid_device * hdev)4580b2c7a89SAndrew Duggan static int rmi_post_resume(struct hid_device *hdev)
45909256360SAndrew Duggan {
4607035f3a4SAndrew Duggan struct rmi_data *data = hid_get_drvdata(hdev);
4610b2c7a89SAndrew Duggan struct rmi_device *rmi_dev = data->xport.rmi_dev;
46209256360SAndrew Duggan int ret;
46309256360SAndrew Duggan
464b786ae8eSAndrew Duggan if (!(data->device_flags & RMI_DEVICE))
465b786ae8eSAndrew Duggan return 0;
466b786ae8eSAndrew Duggan
467cac72b99SLyude /* Make sure the HID device is ready to receive events */
468cac72b99SLyude ret = hid_hw_open(hdev);
4697035f3a4SAndrew Duggan if (ret)
4700b2c7a89SAndrew Duggan return ret;
4717035f3a4SAndrew Duggan
472cac72b99SLyude ret = rmi_reset_attn_mode(hdev);
473cac72b99SLyude if (ret)
474cac72b99SLyude goto out;
475cac72b99SLyude
4760b2c7a89SAndrew Duggan ret = rmi_driver_resume(rmi_dev, false);
47709256360SAndrew Duggan if (ret) {
4780b2c7a89SAndrew Duggan hid_warn(hdev, "Failed to resume device: %d\n", ret);
479cac72b99SLyude goto out;
4809fb6bf02SBenjamin Tissoires }
4819fb6bf02SBenjamin Tissoires
482cac72b99SLyude out:
483cac72b99SLyude hid_hw_close(hdev);
484cac72b99SLyude return ret;
4859fb6bf02SBenjamin Tissoires }
486a278e268SGeert Uytterhoeven #endif /* CONFIG_PM */
4879fb6bf02SBenjamin Tissoires
rmi_hid_reset(struct rmi_transport_dev * xport,u16 reset_addr)4880b2c7a89SAndrew Duggan static int rmi_hid_reset(struct rmi_transport_dev *xport, u16 reset_addr)
4899fb6bf02SBenjamin Tissoires {
4900b2c7a89SAndrew Duggan struct rmi_data *data = container_of(xport, struct rmi_data, xport);
4910b2c7a89SAndrew Duggan struct hid_device *hdev = data->hdev;
4929fb6bf02SBenjamin Tissoires
4930b2c7a89SAndrew Duggan return rmi_reset_attn_mode(hdev);
4949fb6bf02SBenjamin Tissoires }
4959fb6bf02SBenjamin Tissoires
rmi_input_configured(struct hid_device * hdev,struct hid_input * hi)4969154301aSDmitry Torokhov static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
4979fb6bf02SBenjamin Tissoires {
4989fb6bf02SBenjamin Tissoires struct rmi_data *data = hid_get_drvdata(hdev);
4999fb6bf02SBenjamin Tissoires struct input_dev *input = hi->input;
5000b2c7a89SAndrew Duggan int ret = 0;
5019fb6bf02SBenjamin Tissoires
5020b2c7a89SAndrew Duggan if (!(data->device_flags & RMI_DEVICE))
5030b2c7a89SAndrew Duggan return 0;
5040b2c7a89SAndrew Duggan
5050b2c7a89SAndrew Duggan data->xport.input = input;
5069fb6bf02SBenjamin Tissoires
5079fb6bf02SBenjamin Tissoires hid_dbg(hdev, "Opening low level driver\n");
5089fb6bf02SBenjamin Tissoires ret = hid_hw_open(hdev);
5099fb6bf02SBenjamin Tissoires if (ret)
5109154301aSDmitry Torokhov return ret;
5119fb6bf02SBenjamin Tissoires
5129fb6bf02SBenjamin Tissoires /* Allow incoming hid reports */
5139fb6bf02SBenjamin Tissoires hid_device_io_start(hdev);
5149fb6bf02SBenjamin Tissoires
5159fb6bf02SBenjamin Tissoires ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
5169fb6bf02SBenjamin Tissoires if (ret < 0) {
5179fb6bf02SBenjamin Tissoires dev_err(&hdev->dev, "failed to set rmi mode\n");
5189fb6bf02SBenjamin Tissoires goto exit;
5199fb6bf02SBenjamin Tissoires }
5209fb6bf02SBenjamin Tissoires
5219fb6bf02SBenjamin Tissoires ret = rmi_set_page(hdev, 0);
5229fb6bf02SBenjamin Tissoires if (ret < 0) {
5239fb6bf02SBenjamin Tissoires dev_err(&hdev->dev, "failed to set page select to 0.\n");
5249fb6bf02SBenjamin Tissoires goto exit;
5259fb6bf02SBenjamin Tissoires }
5269fb6bf02SBenjamin Tissoires
5270b2c7a89SAndrew Duggan ret = rmi_register_transport_device(&data->xport);
5280b2c7a89SAndrew Duggan if (ret < 0) {
5290b2c7a89SAndrew Duggan dev_err(&hdev->dev, "failed to register transport driver\n");
5309fb6bf02SBenjamin Tissoires goto exit;
5319fb6bf02SBenjamin Tissoires }
5329fb6bf02SBenjamin Tissoires
5339fb6bf02SBenjamin Tissoires set_bit(RMI_STARTED, &data->flags);
5349fb6bf02SBenjamin Tissoires
5359fb6bf02SBenjamin Tissoires exit:
5369fb6bf02SBenjamin Tissoires hid_device_io_stop(hdev);
5379fb6bf02SBenjamin Tissoires hid_hw_close(hdev);
5389154301aSDmitry Torokhov return ret;
5399fb6bf02SBenjamin Tissoires }
5409fb6bf02SBenjamin Tissoires
rmi_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)5419fb6bf02SBenjamin Tissoires static int rmi_input_mapping(struct hid_device *hdev,
5429fb6bf02SBenjamin Tissoires struct hid_input *hi, struct hid_field *field,
5439fb6bf02SBenjamin Tissoires struct hid_usage *usage, unsigned long **bit, int *max)
5449fb6bf02SBenjamin Tissoires {
5452f43de60SAndrew Duggan struct rmi_data *data = hid_get_drvdata(hdev);
5462f43de60SAndrew Duggan
5472f43de60SAndrew Duggan /*
5482f43de60SAndrew Duggan * we want to make HID ignore the advertised HID collection
5492f43de60SAndrew Duggan * for RMI deivces
5502f43de60SAndrew Duggan */
55179364d87SAndrew Duggan if (data->device_flags & RMI_DEVICE) {
55279364d87SAndrew Duggan if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) &&
55379364d87SAndrew Duggan ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON))
55479364d87SAndrew Duggan return 0;
55579364d87SAndrew Duggan
5569fb6bf02SBenjamin Tissoires return -1;
55779364d87SAndrew Duggan }
5582f43de60SAndrew Duggan
5592f43de60SAndrew Duggan return 0;
5602f43de60SAndrew Duggan }
5612f43de60SAndrew Duggan
rmi_check_valid_report_id(struct hid_device * hdev,unsigned type,unsigned id,struct hid_report ** report)5622f43de60SAndrew Duggan static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type,
5632f43de60SAndrew Duggan unsigned id, struct hid_report **report)
5642f43de60SAndrew Duggan {
5652f43de60SAndrew Duggan int i;
5662f43de60SAndrew Duggan
5672f43de60SAndrew Duggan *report = hdev->report_enum[type].report_id_hash[id];
5682f43de60SAndrew Duggan if (*report) {
5692f43de60SAndrew Duggan for (i = 0; i < (*report)->maxfield; i++) {
5702f43de60SAndrew Duggan unsigned app = (*report)->field[i]->application;
5712f43de60SAndrew Duggan if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR)
5722f43de60SAndrew Duggan return 1;
5732f43de60SAndrew Duggan }
5742f43de60SAndrew Duggan }
5752f43de60SAndrew Duggan
5762f43de60SAndrew Duggan return 0;
5779fb6bf02SBenjamin Tissoires }
5789fb6bf02SBenjamin Tissoires
5790b2c7a89SAndrew Duggan static struct rmi_device_platform_data rmi_hid_pdata = {
5800b2c7a89SAndrew Duggan .sensor_pdata = {
5810b2c7a89SAndrew Duggan .sensor_type = rmi_sensor_touchpad,
5820b2c7a89SAndrew Duggan .axis_align.flip_y = true,
5830b2c7a89SAndrew Duggan .dribble = RMI_REG_STATE_ON,
5840b2c7a89SAndrew Duggan .palm_detect = RMI_REG_STATE_OFF,
5850b2c7a89SAndrew Duggan },
5860b2c7a89SAndrew Duggan };
5870b2c7a89SAndrew Duggan
5880b2c7a89SAndrew Duggan static const struct rmi_transport_ops hid_rmi_ops = {
5890b2c7a89SAndrew Duggan .write_block = rmi_hid_write_block,
5900b2c7a89SAndrew Duggan .read_block = rmi_hid_read_block,
5910b2c7a89SAndrew Duggan .reset = rmi_hid_reset,
5920b2c7a89SAndrew Duggan };
5930b2c7a89SAndrew Duggan
rmi_irq_teardown(void * data)5940b2c7a89SAndrew Duggan static void rmi_irq_teardown(void *data)
5950b2c7a89SAndrew Duggan {
5960b2c7a89SAndrew Duggan struct rmi_data *hdata = data;
5970b2c7a89SAndrew Duggan struct irq_domain *domain = hdata->domain;
5980b2c7a89SAndrew Duggan
5990b2c7a89SAndrew Duggan if (!domain)
6000b2c7a89SAndrew Duggan return;
6010b2c7a89SAndrew Duggan
6020b2c7a89SAndrew Duggan irq_dispose_mapping(irq_find_mapping(domain, 0));
6030b2c7a89SAndrew Duggan
6040b2c7a89SAndrew Duggan irq_domain_remove(domain);
6050b2c7a89SAndrew Duggan hdata->domain = NULL;
6060b2c7a89SAndrew Duggan hdata->rmi_irq = 0;
6070b2c7a89SAndrew Duggan }
6080b2c7a89SAndrew Duggan
rmi_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw_irq_num)6090b2c7a89SAndrew Duggan static int rmi_irq_map(struct irq_domain *h, unsigned int virq,
6100b2c7a89SAndrew Duggan irq_hw_number_t hw_irq_num)
6110b2c7a89SAndrew Duggan {
6120b2c7a89SAndrew Duggan irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq);
6130b2c7a89SAndrew Duggan
6140b2c7a89SAndrew Duggan return 0;
6150b2c7a89SAndrew Duggan }
6160b2c7a89SAndrew Duggan
6170b2c7a89SAndrew Duggan static const struct irq_domain_ops rmi_irq_ops = {
6180b2c7a89SAndrew Duggan .map = rmi_irq_map,
6190b2c7a89SAndrew Duggan };
6200b2c7a89SAndrew Duggan
rmi_setup_irq_domain(struct hid_device * hdev)6210b2c7a89SAndrew Duggan static int rmi_setup_irq_domain(struct hid_device *hdev)
6220b2c7a89SAndrew Duggan {
6230b2c7a89SAndrew Duggan struct rmi_data *hdata = hid_get_drvdata(hdev);
6240b2c7a89SAndrew Duggan int ret;
6250b2c7a89SAndrew Duggan
6260b2c7a89SAndrew Duggan hdata->domain = irq_domain_create_linear(hdev->dev.fwnode, 1,
6270b2c7a89SAndrew Duggan &rmi_irq_ops, hdata);
6280b2c7a89SAndrew Duggan if (!hdata->domain)
6290b2c7a89SAndrew Duggan return -ENOMEM;
6300b2c7a89SAndrew Duggan
6310b2c7a89SAndrew Duggan ret = devm_add_action_or_reset(&hdev->dev, &rmi_irq_teardown, hdata);
6320b2c7a89SAndrew Duggan if (ret)
6330b2c7a89SAndrew Duggan return ret;
6340b2c7a89SAndrew Duggan
6350b2c7a89SAndrew Duggan hdata->rmi_irq = irq_create_mapping(hdata->domain, 0);
6360b2c7a89SAndrew Duggan if (hdata->rmi_irq <= 0) {
6370b2c7a89SAndrew Duggan hid_err(hdev, "Can't allocate an IRQ\n");
6380b2c7a89SAndrew Duggan return hdata->rmi_irq < 0 ? hdata->rmi_irq : -ENXIO;
6390b2c7a89SAndrew Duggan }
6400b2c7a89SAndrew Duggan
6410b2c7a89SAndrew Duggan return 0;
6420b2c7a89SAndrew Duggan }
6430b2c7a89SAndrew Duggan
rmi_probe(struct hid_device * hdev,const struct hid_device_id * id)6449fb6bf02SBenjamin Tissoires static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
6459fb6bf02SBenjamin Tissoires {
6469fb6bf02SBenjamin Tissoires struct rmi_data *data = NULL;
6479fb6bf02SBenjamin Tissoires int ret;
6489fb6bf02SBenjamin Tissoires size_t alloc_size;
649dd3edeb6SAndrew Duggan struct hid_report *input_report;
650dd3edeb6SAndrew Duggan struct hid_report *output_report;
6512f43de60SAndrew Duggan struct hid_report *feature_report;
6529fb6bf02SBenjamin Tissoires
6539fb6bf02SBenjamin Tissoires data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
6549fb6bf02SBenjamin Tissoires if (!data)
6559fb6bf02SBenjamin Tissoires return -ENOMEM;
6569fb6bf02SBenjamin Tissoires
6579fb6bf02SBenjamin Tissoires INIT_WORK(&data->reset_work, rmi_reset_work);
6589fb6bf02SBenjamin Tissoires data->hdev = hdev;
6599fb6bf02SBenjamin Tissoires
6609fb6bf02SBenjamin Tissoires hid_set_drvdata(hdev, data);
6619fb6bf02SBenjamin Tissoires
6629fb6bf02SBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
663c94ba060SBenjamin Tissoires hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
6649fb6bf02SBenjamin Tissoires
6659fb6bf02SBenjamin Tissoires ret = hid_parse(hdev);
6669fb6bf02SBenjamin Tissoires if (ret) {
6679fb6bf02SBenjamin Tissoires hid_err(hdev, "parse failed\n");
6689fb6bf02SBenjamin Tissoires return ret;
6699fb6bf02SBenjamin Tissoires }
6709fb6bf02SBenjamin Tissoires
67179364d87SAndrew Duggan if (id->driver_data)
67279364d87SAndrew Duggan data->device_flags = id->driver_data;
67379364d87SAndrew Duggan
6742f43de60SAndrew Duggan /*
6752f43de60SAndrew Duggan * Check for the RMI specific report ids. If they are misisng
6762f43de60SAndrew Duggan * simply return and let the events be processed by hid-input
6772f43de60SAndrew Duggan */
6782f43de60SAndrew Duggan if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT,
6792f43de60SAndrew Duggan RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) {
6802f43de60SAndrew Duggan hid_dbg(hdev, "device does not have set mode feature report\n");
6812f43de60SAndrew Duggan goto start;
6822f43de60SAndrew Duggan }
6832f43de60SAndrew Duggan
6842f43de60SAndrew Duggan if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT,
6852f43de60SAndrew Duggan RMI_ATTN_REPORT_ID, &input_report)) {
6862f43de60SAndrew Duggan hid_dbg(hdev, "device does not have attention input report\n");
6872f43de60SAndrew Duggan goto start;
688dd3edeb6SAndrew Duggan }
689dd3edeb6SAndrew Duggan
690b8aed6eaSAndrew Duggan data->input_report_size = hid_report_len(input_report);
691dd3edeb6SAndrew Duggan
6922f43de60SAndrew Duggan if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT,
6932f43de60SAndrew Duggan RMI_WRITE_REPORT_ID, &output_report)) {
6942f43de60SAndrew Duggan hid_dbg(hdev,
6952f43de60SAndrew Duggan "device does not have rmi write output report\n");
6962f43de60SAndrew Duggan goto start;
697dd3edeb6SAndrew Duggan }
698dd3edeb6SAndrew Duggan
699b8aed6eaSAndrew Duggan data->output_report_size = hid_report_len(output_report);
7009fb6bf02SBenjamin Tissoires
7012f43de60SAndrew Duggan data->device_flags |= RMI_DEVICE;
7029fb6bf02SBenjamin Tissoires alloc_size = data->output_report_size + data->input_report_size;
7039fb6bf02SBenjamin Tissoires
7049fb6bf02SBenjamin Tissoires data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
7059fb6bf02SBenjamin Tissoires if (!data->writeReport) {
7060b2c7a89SAndrew Duggan hid_err(hdev, "failed to allocate buffer for HID reports\n");
7070b2c7a89SAndrew Duggan return -ENOMEM;
7089fb6bf02SBenjamin Tissoires }
7099fb6bf02SBenjamin Tissoires
7109fb6bf02SBenjamin Tissoires data->readReport = data->writeReport + data->output_report_size;
7119fb6bf02SBenjamin Tissoires
7129fb6bf02SBenjamin Tissoires init_waitqueue_head(&data->wait);
7139fb6bf02SBenjamin Tissoires
7149fb6bf02SBenjamin Tissoires mutex_init(&data->page_mutex);
7159fb6bf02SBenjamin Tissoires
7160b2c7a89SAndrew Duggan ret = rmi_setup_irq_domain(hdev);
7170b2c7a89SAndrew Duggan if (ret) {
7180b2c7a89SAndrew Duggan hid_err(hdev, "failed to allocate IRQ domain\n");
7190b2c7a89SAndrew Duggan return ret;
7200b2c7a89SAndrew Duggan }
7210b2c7a89SAndrew Duggan
7220b2c7a89SAndrew Duggan if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS)
723261bfb33SVincent Huang rmi_hid_pdata.gpio_data.disable = true;
7240b2c7a89SAndrew Duggan
7250b2c7a89SAndrew Duggan data->xport.dev = hdev->dev.parent;
7260b2c7a89SAndrew Duggan data->xport.pdata = rmi_hid_pdata;
7270b2c7a89SAndrew Duggan data->xport.pdata.irq = data->rmi_irq;
7280b2c7a89SAndrew Duggan data->xport.proto_name = "hid";
7290b2c7a89SAndrew Duggan data->xport.ops = &hid_rmi_ops;
7300b2c7a89SAndrew Duggan
7312f43de60SAndrew Duggan start:
7329fb6bf02SBenjamin Tissoires ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
7339fb6bf02SBenjamin Tissoires if (ret) {
7349fb6bf02SBenjamin Tissoires hid_err(hdev, "hw start failed\n");
7359fb6bf02SBenjamin Tissoires return ret;
7369fb6bf02SBenjamin Tissoires }
7379fb6bf02SBenjamin Tissoires
7389fb6bf02SBenjamin Tissoires return 0;
7399fb6bf02SBenjamin Tissoires }
7409fb6bf02SBenjamin Tissoires
rmi_remove(struct hid_device * hdev)7419fb6bf02SBenjamin Tissoires static void rmi_remove(struct hid_device *hdev)
7429fb6bf02SBenjamin Tissoires {
7439fb6bf02SBenjamin Tissoires struct rmi_data *hdata = hid_get_drvdata(hdev);
7449fb6bf02SBenjamin Tissoires
7458725aa4fSAndrew Duggan if ((hdata->device_flags & RMI_DEVICE)
7468725aa4fSAndrew Duggan && test_bit(RMI_STARTED, &hdata->flags)) {
7479fb6bf02SBenjamin Tissoires clear_bit(RMI_STARTED, &hdata->flags);
7480b2c7a89SAndrew Duggan cancel_work_sync(&hdata->reset_work);
7490b2c7a89SAndrew Duggan rmi_unregister_transport_device(&hdata->xport);
750ef14a4bfSAndrew Duggan }
7519fb6bf02SBenjamin Tissoires
7529fb6bf02SBenjamin Tissoires hid_hw_stop(hdev);
7539fb6bf02SBenjamin Tissoires }
7549fb6bf02SBenjamin Tissoires
7559fb6bf02SBenjamin Tissoires static const struct hid_device_id rmi_id[] = {
756e9287099SAndrew Duggan { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14),
757e9287099SAndrew Duggan .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
758c7821d0fSAndrew Duggan { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
759c5293409SAndrew Duggan { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
76010235380STobias Auerochs { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5),
76110235380STobias Auerochs .driver_data = RMI_DEVICE_OUTPUT_SET_REPORT },
762ba391e5aSBenjamin Tissoires { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
7639fb6bf02SBenjamin Tissoires { }
7649fb6bf02SBenjamin Tissoires };
7659fb6bf02SBenjamin Tissoires MODULE_DEVICE_TABLE(hid, rmi_id);
7669fb6bf02SBenjamin Tissoires
7679fb6bf02SBenjamin Tissoires static struct hid_driver rmi_driver = {
7689fb6bf02SBenjamin Tissoires .name = "hid-rmi",
7699fb6bf02SBenjamin Tissoires .id_table = rmi_id,
7709fb6bf02SBenjamin Tissoires .probe = rmi_probe,
7719fb6bf02SBenjamin Tissoires .remove = rmi_remove,
7722f43de60SAndrew Duggan .event = rmi_event,
7739fb6bf02SBenjamin Tissoires .raw_event = rmi_raw_event,
774c94ba060SBenjamin Tissoires .report = rmi_report,
7759fb6bf02SBenjamin Tissoires .input_mapping = rmi_input_mapping,
7769fb6bf02SBenjamin Tissoires .input_configured = rmi_input_configured,
7779fb6bf02SBenjamin Tissoires #ifdef CONFIG_PM
77809256360SAndrew Duggan .suspend = rmi_suspend,
7799fb6bf02SBenjamin Tissoires .resume = rmi_post_resume,
7800b2c7a89SAndrew Duggan .reset_resume = rmi_post_resume,
7819fb6bf02SBenjamin Tissoires #endif
7829fb6bf02SBenjamin Tissoires };
7839fb6bf02SBenjamin Tissoires
7849fb6bf02SBenjamin Tissoires module_hid_driver(rmi_driver);
7859fb6bf02SBenjamin Tissoires
7869fb6bf02SBenjamin Tissoires MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
7879fb6bf02SBenjamin Tissoires MODULE_DESCRIPTION("RMI HID driver");
7889fb6bf02SBenjamin Tissoires MODULE_LICENSE("GPL");
789