1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 22b6a321dSAndrew Duggan /* 32b6a321dSAndrew Duggan * Copyright (c) 2011-2016 Synaptics Incorporated 42b6a321dSAndrew Duggan * Copyright (c) 2011 Unixphere 52b6a321dSAndrew Duggan */ 62b6a321dSAndrew Duggan 72b6a321dSAndrew Duggan #include <linux/kernel.h> 82b6a321dSAndrew Duggan #include <linux/rmi.h> 92b6a321dSAndrew Duggan #include <linux/slab.h> 102b6a321dSAndrew Duggan #include <linux/uaccess.h> 112b6a321dSAndrew Duggan #include <linux/of.h> 12ce363f0dSNick Dyer #include <asm/unaligned.h> 132b6a321dSAndrew Duggan #include "rmi_driver.h" 142b6a321dSAndrew Duggan 152b6a321dSAndrew Duggan #define RMI_PRODUCT_ID_LENGTH 10 162b6a321dSAndrew Duggan #define RMI_PRODUCT_INFO_LENGTH 2 172b6a321dSAndrew Duggan 182b6a321dSAndrew Duggan #define RMI_DATE_CODE_LENGTH 3 192b6a321dSAndrew Duggan 202b6a321dSAndrew Duggan #define PRODUCT_ID_OFFSET 0x10 212b6a321dSAndrew Duggan #define PRODUCT_INFO_OFFSET 0x1E 222b6a321dSAndrew Duggan 232b6a321dSAndrew Duggan 242b6a321dSAndrew Duggan /* Force a firmware reset of the sensor */ 252b6a321dSAndrew Duggan #define RMI_F01_CMD_DEVICE_RESET 1 262b6a321dSAndrew Duggan 272b6a321dSAndrew Duggan /* Various F01_RMI_QueryX bits */ 282b6a321dSAndrew Duggan 292b6a321dSAndrew Duggan #define RMI_F01_QRY1_CUSTOM_MAP BIT(0) 302b6a321dSAndrew Duggan #define RMI_F01_QRY1_NON_COMPLIANT BIT(1) 312b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_LTS BIT(2) 322b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_SENSOR_ID BIT(3) 332b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_CHARGER_INP BIT(4) 342b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_ADJ_DOZE BIT(5) 352b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF BIT(6) 362b6a321dSAndrew Duggan #define RMI_F01_QRY1_HAS_QUERY42 BIT(7) 372b6a321dSAndrew Duggan 382b6a321dSAndrew Duggan #define RMI_F01_QRY5_YEAR_MASK 0x1f 392b6a321dSAndrew Duggan #define RMI_F01_QRY6_MONTH_MASK 0x0f 402b6a321dSAndrew Duggan #define RMI_F01_QRY7_DAY_MASK 0x1f 412b6a321dSAndrew Duggan 422b6a321dSAndrew Duggan #define RMI_F01_QRY2_PRODINFO_MASK 0x7f 432b6a321dSAndrew Duggan 442b6a321dSAndrew Duggan #define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */ 452b6a321dSAndrew Duggan 462b6a321dSAndrew Duggan struct f01_basic_properties { 472b6a321dSAndrew Duggan u8 manufacturer_id; 482b6a321dSAndrew Duggan bool has_lts; 492b6a321dSAndrew Duggan bool has_adjustable_doze; 502b6a321dSAndrew Duggan bool has_adjustable_doze_holdoff; 512b6a321dSAndrew Duggan char dom[11]; /* YYYY/MM/DD + '\0' */ 522b6a321dSAndrew Duggan u8 product_id[RMI_PRODUCT_ID_LENGTH + 1]; 532b6a321dSAndrew Duggan u16 productinfo; 542b6a321dSAndrew Duggan u32 firmware_id; 55ce363f0dSNick Dyer u32 package_id; 562b6a321dSAndrew Duggan }; 572b6a321dSAndrew Duggan 582b6a321dSAndrew Duggan /* F01 device status bits */ 592b6a321dSAndrew Duggan 602b6a321dSAndrew Duggan /* Most recent device status event */ 612b6a321dSAndrew Duggan #define RMI_F01_STATUS_CODE(status) ((status) & 0x0f) 622b6a321dSAndrew Duggan /* The device has lost its configuration for some reason. */ 632b6a321dSAndrew Duggan #define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80)) 6429fd0ec2SNick Dyer /* The device is in bootloader mode */ 6529fd0ec2SNick Dyer #define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40) 662b6a321dSAndrew Duggan 672b6a321dSAndrew Duggan /* Control register bits */ 682b6a321dSAndrew Duggan 692b6a321dSAndrew Duggan /* 702b6a321dSAndrew Duggan * Sleep mode controls power management on the device and affects all 712b6a321dSAndrew Duggan * functions of the device. 722b6a321dSAndrew Duggan */ 732b6a321dSAndrew Duggan #define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03 742b6a321dSAndrew Duggan 752b6a321dSAndrew Duggan #define RMI_SLEEP_MODE_NORMAL 0x00 762b6a321dSAndrew Duggan #define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01 772b6a321dSAndrew Duggan #define RMI_SLEEP_MODE_RESERVED0 0x02 782b6a321dSAndrew Duggan #define RMI_SLEEP_MODE_RESERVED1 0x03 792b6a321dSAndrew Duggan 802b6a321dSAndrew Duggan /* 812b6a321dSAndrew Duggan * This bit disables whatever sleep mode may be selected by the sleep_mode 822b6a321dSAndrew Duggan * field and forces the device to run at full power without sleeping. 832b6a321dSAndrew Duggan */ 84e9000b79SNick Dyer #define RMI_F01_CTRL0_NOSLEEP_BIT BIT(2) 852b6a321dSAndrew Duggan 862b6a321dSAndrew Duggan /* 872b6a321dSAndrew Duggan * When this bit is set, the touch controller employs a noise-filtering 882b6a321dSAndrew Duggan * algorithm designed for use with a connected battery charger. 892b6a321dSAndrew Duggan */ 90e9000b79SNick Dyer #define RMI_F01_CTRL0_CHARGER_BIT BIT(5) 912b6a321dSAndrew Duggan 922b6a321dSAndrew Duggan /* 932b6a321dSAndrew Duggan * Sets the report rate for the device. The effect of this setting is 942b6a321dSAndrew Duggan * highly product dependent. Check the spec sheet for your particular 952b6a321dSAndrew Duggan * touch sensor. 962b6a321dSAndrew Duggan */ 97e9000b79SNick Dyer #define RMI_F01_CTRL0_REPORTRATE_BIT BIT(6) 982b6a321dSAndrew Duggan 992b6a321dSAndrew Duggan /* 1002b6a321dSAndrew Duggan * Written by the host as an indicator that the device has been 1012b6a321dSAndrew Duggan * successfully configured. 1022b6a321dSAndrew Duggan */ 103e9000b79SNick Dyer #define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7) 1042b6a321dSAndrew Duggan 1052b6a321dSAndrew Duggan /** 1062b6a321dSAndrew Duggan * @ctrl0 - see the bit definitions above. 1072b6a321dSAndrew Duggan * @doze_interval - controls the interval between checks for finger presence 1082b6a321dSAndrew Duggan * when the touch sensor is in doze mode, in units of 10ms. 1092b6a321dSAndrew Duggan * @wakeup_threshold - controls the capacitance threshold at which the touch 1102b6a321dSAndrew Duggan * sensor will decide to wake up from that low power state. 1112b6a321dSAndrew Duggan * @doze_holdoff - controls how long the touch sensor waits after the last 1122b6a321dSAndrew Duggan * finger lifts before entering the doze state, in units of 100ms. 1132b6a321dSAndrew Duggan */ 1142b6a321dSAndrew Duggan struct f01_device_control { 1152b6a321dSAndrew Duggan u8 ctrl0; 1162b6a321dSAndrew Duggan u8 doze_interval; 1172b6a321dSAndrew Duggan u8 wakeup_threshold; 1182b6a321dSAndrew Duggan u8 doze_holdoff; 1192b6a321dSAndrew Duggan }; 1202b6a321dSAndrew Duggan 1212b6a321dSAndrew Duggan struct f01_data { 1222b6a321dSAndrew Duggan struct f01_basic_properties properties; 1232b6a321dSAndrew Duggan struct f01_device_control device_control; 1242b6a321dSAndrew Duggan 1252b6a321dSAndrew Duggan u16 doze_interval_addr; 1262b6a321dSAndrew Duggan u16 wakeup_threshold_addr; 1272b6a321dSAndrew Duggan u16 doze_holdoff_addr; 1282b6a321dSAndrew Duggan 1292b6a321dSAndrew Duggan bool suspended; 1302b6a321dSAndrew Duggan bool old_nosleep; 1312b6a321dSAndrew Duggan 1322b6a321dSAndrew Duggan unsigned int num_of_irq_regs; 1332b6a321dSAndrew Duggan }; 1342b6a321dSAndrew Duggan 1352b6a321dSAndrew Duggan static int rmi_f01_read_properties(struct rmi_device *rmi_dev, 1362b6a321dSAndrew Duggan u16 query_base_addr, 1372b6a321dSAndrew Duggan struct f01_basic_properties *props) 1382b6a321dSAndrew Duggan { 1392b6a321dSAndrew Duggan u8 queries[RMI_F01_BASIC_QUERY_LEN]; 1402b6a321dSAndrew Duggan int ret; 1412b6a321dSAndrew Duggan int query_offset = query_base_addr; 1422b6a321dSAndrew Duggan bool has_ds4_queries = false; 1432b6a321dSAndrew Duggan bool has_query42 = false; 1442b6a321dSAndrew Duggan bool has_sensor_id = false; 1452b6a321dSAndrew Duggan bool has_package_id_query = false; 1462b6a321dSAndrew Duggan bool has_build_id_query = false; 1472b6a321dSAndrew Duggan u16 prod_info_addr; 1482b6a321dSAndrew Duggan u8 ds4_query_len; 1492b6a321dSAndrew Duggan 1502b6a321dSAndrew Duggan ret = rmi_read_block(rmi_dev, query_offset, 1512b6a321dSAndrew Duggan queries, RMI_F01_BASIC_QUERY_LEN); 1522b6a321dSAndrew Duggan if (ret) { 1532b6a321dSAndrew Duggan dev_err(&rmi_dev->dev, 1542b6a321dSAndrew Duggan "Failed to read device query registers: %d\n", ret); 1552b6a321dSAndrew Duggan return ret; 1562b6a321dSAndrew Duggan } 1572b6a321dSAndrew Duggan 1582b6a321dSAndrew Duggan prod_info_addr = query_offset + 17; 1592b6a321dSAndrew Duggan query_offset += RMI_F01_BASIC_QUERY_LEN; 1602b6a321dSAndrew Duggan 1612b6a321dSAndrew Duggan /* Now parse what we got */ 1622b6a321dSAndrew Duggan props->manufacturer_id = queries[0]; 1632b6a321dSAndrew Duggan 1642b6a321dSAndrew Duggan props->has_lts = queries[1] & RMI_F01_QRY1_HAS_LTS; 1652b6a321dSAndrew Duggan props->has_adjustable_doze = 1662b6a321dSAndrew Duggan queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE; 1672b6a321dSAndrew Duggan props->has_adjustable_doze_holdoff = 1682b6a321dSAndrew Duggan queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF; 1692b6a321dSAndrew Duggan has_query42 = queries[1] & RMI_F01_QRY1_HAS_QUERY42; 1702b6a321dSAndrew Duggan has_sensor_id = queries[1] & RMI_F01_QRY1_HAS_SENSOR_ID; 1712b6a321dSAndrew Duggan 1722b6a321dSAndrew Duggan snprintf(props->dom, sizeof(props->dom), "20%02d/%02d/%02d", 1732b6a321dSAndrew Duggan queries[5] & RMI_F01_QRY5_YEAR_MASK, 1742b6a321dSAndrew Duggan queries[6] & RMI_F01_QRY6_MONTH_MASK, 1752b6a321dSAndrew Duggan queries[7] & RMI_F01_QRY7_DAY_MASK); 1762b6a321dSAndrew Duggan 1772b6a321dSAndrew Duggan memcpy(props->product_id, &queries[11], 1782b6a321dSAndrew Duggan RMI_PRODUCT_ID_LENGTH); 1792b6a321dSAndrew Duggan props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0'; 1802b6a321dSAndrew Duggan 1812b6a321dSAndrew Duggan props->productinfo = 1822b6a321dSAndrew Duggan ((queries[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) | 1832b6a321dSAndrew Duggan (queries[3] & RMI_F01_QRY2_PRODINFO_MASK); 1842b6a321dSAndrew Duggan 1852b6a321dSAndrew Duggan if (has_sensor_id) 1862b6a321dSAndrew Duggan query_offset++; 1872b6a321dSAndrew Duggan 1882b6a321dSAndrew Duggan if (has_query42) { 1892b6a321dSAndrew Duggan ret = rmi_read(rmi_dev, query_offset, queries); 1902b6a321dSAndrew Duggan if (ret) { 1912b6a321dSAndrew Duggan dev_err(&rmi_dev->dev, 1922b6a321dSAndrew Duggan "Failed to read query 42 register: %d\n", ret); 1932b6a321dSAndrew Duggan return ret; 1942b6a321dSAndrew Duggan } 1952b6a321dSAndrew Duggan 1962b6a321dSAndrew Duggan has_ds4_queries = !!(queries[0] & BIT(0)); 1972b6a321dSAndrew Duggan query_offset++; 1982b6a321dSAndrew Duggan } 1992b6a321dSAndrew Duggan 2002b6a321dSAndrew Duggan if (has_ds4_queries) { 2012b6a321dSAndrew Duggan ret = rmi_read(rmi_dev, query_offset, &ds4_query_len); 2022b6a321dSAndrew Duggan if (ret) { 2032b6a321dSAndrew Duggan dev_err(&rmi_dev->dev, 2042b6a321dSAndrew Duggan "Failed to read DS4 queries length: %d\n", ret); 2052b6a321dSAndrew Duggan return ret; 2062b6a321dSAndrew Duggan } 2072b6a321dSAndrew Duggan query_offset++; 2082b6a321dSAndrew Duggan 2092b6a321dSAndrew Duggan if (ds4_query_len > 0) { 2102b6a321dSAndrew Duggan ret = rmi_read(rmi_dev, query_offset, queries); 2112b6a321dSAndrew Duggan if (ret) { 2122b6a321dSAndrew Duggan dev_err(&rmi_dev->dev, 2132b6a321dSAndrew Duggan "Failed to read DS4 queries: %d\n", 2142b6a321dSAndrew Duggan ret); 2152b6a321dSAndrew Duggan return ret; 2162b6a321dSAndrew Duggan } 2172b6a321dSAndrew Duggan 2182b6a321dSAndrew Duggan has_package_id_query = !!(queries[0] & BIT(0)); 2192b6a321dSAndrew Duggan has_build_id_query = !!(queries[0] & BIT(1)); 2202b6a321dSAndrew Duggan } 2212b6a321dSAndrew Duggan 222ce363f0dSNick Dyer if (has_package_id_query) { 223ce363f0dSNick Dyer ret = rmi_read_block(rmi_dev, prod_info_addr, 224ce363f0dSNick Dyer queries, sizeof(__le64)); 225ce363f0dSNick Dyer if (ret) { 226ce363f0dSNick Dyer dev_err(&rmi_dev->dev, 227ce363f0dSNick Dyer "Failed to read package info: %d\n", 228ce363f0dSNick Dyer ret); 229ce363f0dSNick Dyer return ret; 230ce363f0dSNick Dyer } 231ce363f0dSNick Dyer 232ce363f0dSNick Dyer props->package_id = get_unaligned_le64(queries); 2332b6a321dSAndrew Duggan prod_info_addr++; 234ce363f0dSNick Dyer } 2352b6a321dSAndrew Duggan 2362b6a321dSAndrew Duggan if (has_build_id_query) { 2372b6a321dSAndrew Duggan ret = rmi_read_block(rmi_dev, prod_info_addr, queries, 2382b6a321dSAndrew Duggan 3); 2392b6a321dSAndrew Duggan if (ret) { 2402b6a321dSAndrew Duggan dev_err(&rmi_dev->dev, 2412b6a321dSAndrew Duggan "Failed to read product info: %d\n", 2422b6a321dSAndrew Duggan ret); 2432b6a321dSAndrew Duggan return ret; 2442b6a321dSAndrew Duggan } 2452b6a321dSAndrew Duggan 2462b6a321dSAndrew Duggan props->firmware_id = queries[1] << 8 | queries[0]; 2472b6a321dSAndrew Duggan props->firmware_id += queries[2] * 65536; 2482b6a321dSAndrew Duggan } 2492b6a321dSAndrew Duggan } 2502b6a321dSAndrew Duggan 2512b6a321dSAndrew Duggan return 0; 2522b6a321dSAndrew Duggan } 2532b6a321dSAndrew Duggan 254ce363f0dSNick Dyer const char *rmi_f01_get_product_ID(struct rmi_function *fn) 2552b6a321dSAndrew Duggan { 2562b6a321dSAndrew Duggan struct f01_data *f01 = dev_get_drvdata(&fn->dev); 2572b6a321dSAndrew Duggan 2582b6a321dSAndrew Duggan return f01->properties.product_id; 2592b6a321dSAndrew Duggan } 2602b6a321dSAndrew Duggan 261ce363f0dSNick Dyer static ssize_t rmi_driver_manufacturer_id_show(struct device *dev, 262ce363f0dSNick Dyer struct device_attribute *dattr, 263ce363f0dSNick Dyer char *buf) 264ce363f0dSNick Dyer { 265ce363f0dSNick Dyer struct rmi_driver_data *data = dev_get_drvdata(dev); 266ce363f0dSNick Dyer struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 267ce363f0dSNick Dyer 268ce363f0dSNick Dyer return scnprintf(buf, PAGE_SIZE, "%d\n", 269ce363f0dSNick Dyer f01->properties.manufacturer_id); 270ce363f0dSNick Dyer } 271ce363f0dSNick Dyer 272ce363f0dSNick Dyer static DEVICE_ATTR(manufacturer_id, 0444, 273ce363f0dSNick Dyer rmi_driver_manufacturer_id_show, NULL); 274ce363f0dSNick Dyer 275ce363f0dSNick Dyer static ssize_t rmi_driver_dom_show(struct device *dev, 276ce363f0dSNick Dyer struct device_attribute *dattr, char *buf) 277ce363f0dSNick Dyer { 278ce363f0dSNick Dyer struct rmi_driver_data *data = dev_get_drvdata(dev); 279ce363f0dSNick Dyer struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 280ce363f0dSNick Dyer 281ce363f0dSNick Dyer return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.dom); 282ce363f0dSNick Dyer } 283ce363f0dSNick Dyer 284ce363f0dSNick Dyer static DEVICE_ATTR(date_of_manufacture, 0444, rmi_driver_dom_show, NULL); 285ce363f0dSNick Dyer 286ce363f0dSNick Dyer static ssize_t rmi_driver_product_id_show(struct device *dev, 287ce363f0dSNick Dyer struct device_attribute *dattr, 288ce363f0dSNick Dyer char *buf) 289ce363f0dSNick Dyer { 290ce363f0dSNick Dyer struct rmi_driver_data *data = dev_get_drvdata(dev); 291ce363f0dSNick Dyer struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 292ce363f0dSNick Dyer 293ce363f0dSNick Dyer return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.product_id); 294ce363f0dSNick Dyer } 295ce363f0dSNick Dyer 296ce363f0dSNick Dyer static DEVICE_ATTR(product_id, 0444, rmi_driver_product_id_show, NULL); 297ce363f0dSNick Dyer 298ce363f0dSNick Dyer static ssize_t rmi_driver_firmware_id_show(struct device *dev, 299ce363f0dSNick Dyer struct device_attribute *dattr, 300ce363f0dSNick Dyer char *buf) 301ce363f0dSNick Dyer { 302ce363f0dSNick Dyer struct rmi_driver_data *data = dev_get_drvdata(dev); 303ce363f0dSNick Dyer struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 304ce363f0dSNick Dyer 305ce363f0dSNick Dyer return scnprintf(buf, PAGE_SIZE, "%d\n", f01->properties.firmware_id); 306ce363f0dSNick Dyer } 307ce363f0dSNick Dyer 308ce363f0dSNick Dyer static DEVICE_ATTR(firmware_id, 0444, rmi_driver_firmware_id_show, NULL); 309ce363f0dSNick Dyer 310ce363f0dSNick Dyer static ssize_t rmi_driver_package_id_show(struct device *dev, 311ce363f0dSNick Dyer struct device_attribute *dattr, 312ce363f0dSNick Dyer char *buf) 313ce363f0dSNick Dyer { 314ce363f0dSNick Dyer struct rmi_driver_data *data = dev_get_drvdata(dev); 315ce363f0dSNick Dyer struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 316ce363f0dSNick Dyer 317ce363f0dSNick Dyer u32 package_id = f01->properties.package_id; 318ce363f0dSNick Dyer 319ce363f0dSNick Dyer return scnprintf(buf, PAGE_SIZE, "%04x.%04x\n", 320ce363f0dSNick Dyer package_id & 0xffff, (package_id >> 16) & 0xffff); 321ce363f0dSNick Dyer } 322ce363f0dSNick Dyer 323ce363f0dSNick Dyer static DEVICE_ATTR(package_id, 0444, rmi_driver_package_id_show, NULL); 324ce363f0dSNick Dyer 325ce363f0dSNick Dyer static struct attribute *rmi_f01_attrs[] = { 326ce363f0dSNick Dyer &dev_attr_manufacturer_id.attr, 327ce363f0dSNick Dyer &dev_attr_date_of_manufacture.attr, 328ce363f0dSNick Dyer &dev_attr_product_id.attr, 329ce363f0dSNick Dyer &dev_attr_firmware_id.attr, 330ce363f0dSNick Dyer &dev_attr_package_id.attr, 331ce363f0dSNick Dyer NULL 332ce363f0dSNick Dyer }; 333ce363f0dSNick Dyer 3340d4b8e36SArvind Yadav static const struct attribute_group rmi_f01_attr_group = { 335ce363f0dSNick Dyer .attrs = rmi_f01_attrs, 336ce363f0dSNick Dyer }; 337ce363f0dSNick Dyer 338d8a8b3edSAndrew Duggan #ifdef CONFIG_OF 339d8a8b3edSAndrew Duggan static int rmi_f01_of_probe(struct device *dev, 340d8a8b3edSAndrew Duggan struct rmi_device_platform_data *pdata) 341d8a8b3edSAndrew Duggan { 342d8a8b3edSAndrew Duggan int retval; 343d8a8b3edSAndrew Duggan u32 val; 344d8a8b3edSAndrew Duggan 345d8a8b3edSAndrew Duggan retval = rmi_of_property_read_u32(dev, 346d8a8b3edSAndrew Duggan (u32 *)&pdata->power_management.nosleep, 347d8a8b3edSAndrew Duggan "syna,nosleep-mode", 1); 348d8a8b3edSAndrew Duggan if (retval) 349d8a8b3edSAndrew Duggan return retval; 350d8a8b3edSAndrew Duggan 351d8a8b3edSAndrew Duggan retval = rmi_of_property_read_u32(dev, &val, 352d8a8b3edSAndrew Duggan "syna,wakeup-threshold", 1); 353d8a8b3edSAndrew Duggan if (retval) 354d8a8b3edSAndrew Duggan return retval; 355d8a8b3edSAndrew Duggan 356d8a8b3edSAndrew Duggan pdata->power_management.wakeup_threshold = val; 357d8a8b3edSAndrew Duggan 358d8a8b3edSAndrew Duggan retval = rmi_of_property_read_u32(dev, &val, 359d8a8b3edSAndrew Duggan "syna,doze-holdoff-ms", 1); 360d8a8b3edSAndrew Duggan if (retval) 361d8a8b3edSAndrew Duggan return retval; 362d8a8b3edSAndrew Duggan 363d8a8b3edSAndrew Duggan pdata->power_management.doze_holdoff = val * 100; 364d8a8b3edSAndrew Duggan 365d8a8b3edSAndrew Duggan retval = rmi_of_property_read_u32(dev, &val, 366d8a8b3edSAndrew Duggan "syna,doze-interval-ms", 1); 367d8a8b3edSAndrew Duggan if (retval) 368d8a8b3edSAndrew Duggan return retval; 369d8a8b3edSAndrew Duggan 370d8a8b3edSAndrew Duggan pdata->power_management.doze_interval = val / 10; 371d8a8b3edSAndrew Duggan 372d8a8b3edSAndrew Duggan return 0; 373d8a8b3edSAndrew Duggan } 374d8a8b3edSAndrew Duggan #else 375d8a8b3edSAndrew Duggan static inline int rmi_f01_of_probe(struct device *dev, 376d8a8b3edSAndrew Duggan struct rmi_device_platform_data *pdata) 377d8a8b3edSAndrew Duggan { 378d8a8b3edSAndrew Duggan return -ENODEV; 379d8a8b3edSAndrew Duggan } 380d8a8b3edSAndrew Duggan #endif 381d8a8b3edSAndrew Duggan 3822b6a321dSAndrew Duggan static int rmi_f01_probe(struct rmi_function *fn) 3832b6a321dSAndrew Duggan { 3842b6a321dSAndrew Duggan struct rmi_device *rmi_dev = fn->rmi_dev; 3852b6a321dSAndrew Duggan struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev); 3862b6a321dSAndrew Duggan struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); 3872b6a321dSAndrew Duggan struct f01_data *f01; 3882b6a321dSAndrew Duggan int error; 3892b6a321dSAndrew Duggan u16 ctrl_base_addr = fn->fd.control_base_addr; 3902b6a321dSAndrew Duggan u8 device_status; 3912b6a321dSAndrew Duggan u8 temp; 3922b6a321dSAndrew Duggan 393d8a8b3edSAndrew Duggan if (fn->dev.of_node) { 394d8a8b3edSAndrew Duggan error = rmi_f01_of_probe(&fn->dev, pdata); 395d8a8b3edSAndrew Duggan if (error) 396d8a8b3edSAndrew Duggan return error; 397d8a8b3edSAndrew Duggan } 398d8a8b3edSAndrew Duggan 3992b6a321dSAndrew Duggan f01 = devm_kzalloc(&fn->dev, sizeof(struct f01_data), GFP_KERNEL); 4002b6a321dSAndrew Duggan if (!f01) 4012b6a321dSAndrew Duggan return -ENOMEM; 4022b6a321dSAndrew Duggan 4032b6a321dSAndrew Duggan f01->num_of_irq_regs = driver_data->num_of_irq_regs; 4042b6a321dSAndrew Duggan 4052b6a321dSAndrew Duggan /* 4062b6a321dSAndrew Duggan * Set the configured bit and (optionally) other important stuff 4072b6a321dSAndrew Duggan * in the device control register. 4082b6a321dSAndrew Duggan */ 4092b6a321dSAndrew Duggan 4102b6a321dSAndrew Duggan error = rmi_read(rmi_dev, fn->fd.control_base_addr, 4112b6a321dSAndrew Duggan &f01->device_control.ctrl0); 4122b6a321dSAndrew Duggan if (error) { 4132b6a321dSAndrew Duggan dev_err(&fn->dev, "Failed to read F01 control: %d\n", error); 4142b6a321dSAndrew Duggan return error; 4152b6a321dSAndrew Duggan } 4162b6a321dSAndrew Duggan 4172b6a321dSAndrew Duggan switch (pdata->power_management.nosleep) { 4182775e523SAndrew Duggan case RMI_REG_STATE_DEFAULT: 4192b6a321dSAndrew Duggan break; 4202775e523SAndrew Duggan case RMI_REG_STATE_OFF: 421e9000b79SNick Dyer f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; 4222b6a321dSAndrew Duggan break; 4232775e523SAndrew Duggan case RMI_REG_STATE_ON: 424e9000b79SNick Dyer f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 4252b6a321dSAndrew Duggan break; 4262b6a321dSAndrew Duggan } 4272b6a321dSAndrew Duggan 4282b6a321dSAndrew Duggan /* 4292b6a321dSAndrew Duggan * Sleep mode might be set as a hangover from a system crash or 4302b6a321dSAndrew Duggan * reboot without power cycle. If so, clear it so the sensor 4312b6a321dSAndrew Duggan * is certain to function. 4322b6a321dSAndrew Duggan */ 4332b6a321dSAndrew Duggan if ((f01->device_control.ctrl0 & RMI_F01_CTRL0_SLEEP_MODE_MASK) != 4342b6a321dSAndrew Duggan RMI_SLEEP_MODE_NORMAL) { 4352b6a321dSAndrew Duggan dev_warn(&fn->dev, 4362b6a321dSAndrew Duggan "WARNING: Non-zero sleep mode found. Clearing...\n"); 4372b6a321dSAndrew Duggan f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 4382b6a321dSAndrew Duggan } 4392b6a321dSAndrew Duggan 440e9000b79SNick Dyer f01->device_control.ctrl0 |= RMI_F01_CTRL0_CONFIGURED_BIT; 4412b6a321dSAndrew Duggan 4422b6a321dSAndrew Duggan error = rmi_write(rmi_dev, fn->fd.control_base_addr, 4432b6a321dSAndrew Duggan f01->device_control.ctrl0); 4442b6a321dSAndrew Duggan if (error) { 4452b6a321dSAndrew Duggan dev_err(&fn->dev, "Failed to write F01 control: %d\n", error); 4462b6a321dSAndrew Duggan return error; 4472b6a321dSAndrew Duggan } 4482b6a321dSAndrew Duggan 4492b6a321dSAndrew Duggan /* Dummy read in order to clear irqs */ 4502b6a321dSAndrew Duggan error = rmi_read(rmi_dev, fn->fd.data_base_addr + 1, &temp); 4512b6a321dSAndrew Duggan if (error < 0) { 4522b6a321dSAndrew Duggan dev_err(&fn->dev, "Failed to read Interrupt Status.\n"); 4532b6a321dSAndrew Duggan return error; 4542b6a321dSAndrew Duggan } 4552b6a321dSAndrew Duggan 4562b6a321dSAndrew Duggan error = rmi_f01_read_properties(rmi_dev, fn->fd.query_base_addr, 4572b6a321dSAndrew Duggan &f01->properties); 4582b6a321dSAndrew Duggan if (error < 0) { 4592b6a321dSAndrew Duggan dev_err(&fn->dev, "Failed to read F01 properties.\n"); 4602b6a321dSAndrew Duggan return error; 4612b6a321dSAndrew Duggan } 4622b6a321dSAndrew Duggan 4632b6a321dSAndrew Duggan dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s, fw id: %d\n", 4642b6a321dSAndrew Duggan f01->properties.manufacturer_id == 1 ? "Synaptics" : "unknown", 4652b6a321dSAndrew Duggan f01->properties.product_id, f01->properties.firmware_id); 4662b6a321dSAndrew Duggan 4672b6a321dSAndrew Duggan /* Advance to interrupt control registers, then skip over them. */ 4682b6a321dSAndrew Duggan ctrl_base_addr++; 4692b6a321dSAndrew Duggan ctrl_base_addr += f01->num_of_irq_regs; 4702b6a321dSAndrew Duggan 4712b6a321dSAndrew Duggan /* read control register */ 4722b6a321dSAndrew Duggan if (f01->properties.has_adjustable_doze) { 4732b6a321dSAndrew Duggan f01->doze_interval_addr = ctrl_base_addr; 4742b6a321dSAndrew Duggan ctrl_base_addr++; 4752b6a321dSAndrew Duggan 4762b6a321dSAndrew Duggan if (pdata->power_management.doze_interval) { 4772b6a321dSAndrew Duggan f01->device_control.doze_interval = 4782b6a321dSAndrew Duggan pdata->power_management.doze_interval; 4792b6a321dSAndrew Duggan error = rmi_write(rmi_dev, f01->doze_interval_addr, 4802b6a321dSAndrew Duggan f01->device_control.doze_interval); 4812b6a321dSAndrew Duggan if (error) { 4822b6a321dSAndrew Duggan dev_err(&fn->dev, 4832b6a321dSAndrew Duggan "Failed to configure F01 doze interval register: %d\n", 4842b6a321dSAndrew Duggan error); 4852b6a321dSAndrew Duggan return error; 4862b6a321dSAndrew Duggan } 4872b6a321dSAndrew Duggan } else { 4882b6a321dSAndrew Duggan error = rmi_read(rmi_dev, f01->doze_interval_addr, 4892b6a321dSAndrew Duggan &f01->device_control.doze_interval); 4902b6a321dSAndrew Duggan if (error) { 4912b6a321dSAndrew Duggan dev_err(&fn->dev, 4922b6a321dSAndrew Duggan "Failed to read F01 doze interval register: %d\n", 4932b6a321dSAndrew Duggan error); 4942b6a321dSAndrew Duggan return error; 4952b6a321dSAndrew Duggan } 4962b6a321dSAndrew Duggan } 4972b6a321dSAndrew Duggan 4982b6a321dSAndrew Duggan f01->wakeup_threshold_addr = ctrl_base_addr; 4992b6a321dSAndrew Duggan ctrl_base_addr++; 5002b6a321dSAndrew Duggan 5012b6a321dSAndrew Duggan if (pdata->power_management.wakeup_threshold) { 5022b6a321dSAndrew Duggan f01->device_control.wakeup_threshold = 5032b6a321dSAndrew Duggan pdata->power_management.wakeup_threshold; 5042b6a321dSAndrew Duggan error = rmi_write(rmi_dev, f01->wakeup_threshold_addr, 5052b6a321dSAndrew Duggan f01->device_control.wakeup_threshold); 5062b6a321dSAndrew Duggan if (error) { 5072b6a321dSAndrew Duggan dev_err(&fn->dev, 5082b6a321dSAndrew Duggan "Failed to configure F01 wakeup threshold register: %d\n", 5092b6a321dSAndrew Duggan error); 5102b6a321dSAndrew Duggan return error; 5112b6a321dSAndrew Duggan } 5122b6a321dSAndrew Duggan } else { 5132b6a321dSAndrew Duggan error = rmi_read(rmi_dev, f01->wakeup_threshold_addr, 5142b6a321dSAndrew Duggan &f01->device_control.wakeup_threshold); 5152b6a321dSAndrew Duggan if (error < 0) { 5162b6a321dSAndrew Duggan dev_err(&fn->dev, 5172b6a321dSAndrew Duggan "Failed to read F01 wakeup threshold register: %d\n", 5182b6a321dSAndrew Duggan error); 5192b6a321dSAndrew Duggan return error; 5202b6a321dSAndrew Duggan } 5212b6a321dSAndrew Duggan } 5222b6a321dSAndrew Duggan } 5232b6a321dSAndrew Duggan 5242b6a321dSAndrew Duggan if (f01->properties.has_lts) 5252b6a321dSAndrew Duggan ctrl_base_addr++; 5262b6a321dSAndrew Duggan 5272b6a321dSAndrew Duggan if (f01->properties.has_adjustable_doze_holdoff) { 5282b6a321dSAndrew Duggan f01->doze_holdoff_addr = ctrl_base_addr; 5292b6a321dSAndrew Duggan ctrl_base_addr++; 5302b6a321dSAndrew Duggan 5312b6a321dSAndrew Duggan if (pdata->power_management.doze_holdoff) { 5322b6a321dSAndrew Duggan f01->device_control.doze_holdoff = 5332b6a321dSAndrew Duggan pdata->power_management.doze_holdoff; 5342b6a321dSAndrew Duggan error = rmi_write(rmi_dev, f01->doze_holdoff_addr, 5352b6a321dSAndrew Duggan f01->device_control.doze_holdoff); 5362b6a321dSAndrew Duggan if (error) { 5372b6a321dSAndrew Duggan dev_err(&fn->dev, 5382b6a321dSAndrew Duggan "Failed to configure F01 doze holdoff register: %d\n", 5392b6a321dSAndrew Duggan error); 5402b6a321dSAndrew Duggan return error; 5412b6a321dSAndrew Duggan } 5422b6a321dSAndrew Duggan } else { 5432b6a321dSAndrew Duggan error = rmi_read(rmi_dev, f01->doze_holdoff_addr, 5442b6a321dSAndrew Duggan &f01->device_control.doze_holdoff); 5452b6a321dSAndrew Duggan if (error) { 5462b6a321dSAndrew Duggan dev_err(&fn->dev, 5472b6a321dSAndrew Duggan "Failed to read F01 doze holdoff register: %d\n", 5482b6a321dSAndrew Duggan error); 5492b6a321dSAndrew Duggan return error; 5502b6a321dSAndrew Duggan } 5512b6a321dSAndrew Duggan } 5522b6a321dSAndrew Duggan } 5532b6a321dSAndrew Duggan 5542b6a321dSAndrew Duggan error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status); 5552b6a321dSAndrew Duggan if (error < 0) { 5562b6a321dSAndrew Duggan dev_err(&fn->dev, 5572b6a321dSAndrew Duggan "Failed to read device status: %d\n", error); 5582b6a321dSAndrew Duggan return error; 5592b6a321dSAndrew Duggan } 5602b6a321dSAndrew Duggan 5612b6a321dSAndrew Duggan if (RMI_F01_STATUS_UNCONFIGURED(device_status)) { 5622b6a321dSAndrew Duggan dev_err(&fn->dev, 5632b6a321dSAndrew Duggan "Device was reset during configuration process, status: %#02x!\n", 5642b6a321dSAndrew Duggan RMI_F01_STATUS_CODE(device_status)); 5652b6a321dSAndrew Duggan return -EINVAL; 5662b6a321dSAndrew Duggan } 5672b6a321dSAndrew Duggan 5682b6a321dSAndrew Duggan dev_set_drvdata(&fn->dev, f01); 5692b6a321dSAndrew Duggan 570060403f3SNick Dyer error = sysfs_create_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group); 571ce363f0dSNick Dyer if (error) 572060403f3SNick Dyer dev_warn(&fn->dev, "Failed to create sysfs group: %d\n", error); 573ce363f0dSNick Dyer 5742b6a321dSAndrew Duggan return 0; 5752b6a321dSAndrew Duggan } 5762b6a321dSAndrew Duggan 577060403f3SNick Dyer static void rmi_f01_remove(struct rmi_function *fn) 578060403f3SNick Dyer { 579060403f3SNick Dyer /* Note that the bus device is used, not the F01 device */ 580060403f3SNick Dyer sysfs_remove_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group); 581060403f3SNick Dyer } 582060403f3SNick Dyer 5832b6a321dSAndrew Duggan static int rmi_f01_config(struct rmi_function *fn) 5842b6a321dSAndrew Duggan { 5852b6a321dSAndrew Duggan struct f01_data *f01 = dev_get_drvdata(&fn->dev); 5862b6a321dSAndrew Duggan int error; 5872b6a321dSAndrew Duggan 5882b6a321dSAndrew Duggan error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 5892b6a321dSAndrew Duggan f01->device_control.ctrl0); 5902b6a321dSAndrew Duggan if (error) { 5912b6a321dSAndrew Duggan dev_err(&fn->dev, 5922b6a321dSAndrew Duggan "Failed to write device_control register: %d\n", error); 5932b6a321dSAndrew Duggan return error; 5942b6a321dSAndrew Duggan } 5952b6a321dSAndrew Duggan 5962b6a321dSAndrew Duggan if (f01->properties.has_adjustable_doze) { 5972b6a321dSAndrew Duggan error = rmi_write(fn->rmi_dev, f01->doze_interval_addr, 5982b6a321dSAndrew Duggan f01->device_control.doze_interval); 5992b6a321dSAndrew Duggan if (error) { 6002b6a321dSAndrew Duggan dev_err(&fn->dev, 6012b6a321dSAndrew Duggan "Failed to write doze interval: %d\n", error); 6022b6a321dSAndrew Duggan return error; 6032b6a321dSAndrew Duggan } 6042b6a321dSAndrew Duggan 6052b6a321dSAndrew Duggan error = rmi_write_block(fn->rmi_dev, 6062b6a321dSAndrew Duggan f01->wakeup_threshold_addr, 6072b6a321dSAndrew Duggan &f01->device_control.wakeup_threshold, 6082b6a321dSAndrew Duggan sizeof(u8)); 6092b6a321dSAndrew Duggan if (error) { 6102b6a321dSAndrew Duggan dev_err(&fn->dev, 6112b6a321dSAndrew Duggan "Failed to write wakeup threshold: %d\n", 6122b6a321dSAndrew Duggan error); 6132b6a321dSAndrew Duggan return error; 6142b6a321dSAndrew Duggan } 6152b6a321dSAndrew Duggan } 6162b6a321dSAndrew Duggan 6172b6a321dSAndrew Duggan if (f01->properties.has_adjustable_doze_holdoff) { 6182b6a321dSAndrew Duggan error = rmi_write(fn->rmi_dev, f01->doze_holdoff_addr, 6192b6a321dSAndrew Duggan f01->device_control.doze_holdoff); 6202b6a321dSAndrew Duggan if (error) { 6212b6a321dSAndrew Duggan dev_err(&fn->dev, 6222b6a321dSAndrew Duggan "Failed to write doze holdoff: %d\n", error); 6232b6a321dSAndrew Duggan return error; 6242b6a321dSAndrew Duggan } 6252b6a321dSAndrew Duggan } 6262b6a321dSAndrew Duggan 6272b6a321dSAndrew Duggan return 0; 6282b6a321dSAndrew Duggan } 6292b6a321dSAndrew Duggan 6302b6a321dSAndrew Duggan static int rmi_f01_suspend(struct rmi_function *fn) 6312b6a321dSAndrew Duggan { 6322b6a321dSAndrew Duggan struct f01_data *f01 = dev_get_drvdata(&fn->dev); 6332b6a321dSAndrew Duggan int error; 6342b6a321dSAndrew Duggan 6352b6a321dSAndrew Duggan f01->old_nosleep = 636e9000b79SNick Dyer f01->device_control.ctrl0 & RMI_F01_CTRL0_NOSLEEP_BIT; 637e9000b79SNick Dyer f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; 6382b6a321dSAndrew Duggan 6392b6a321dSAndrew Duggan f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 6402b6a321dSAndrew Duggan if (device_may_wakeup(fn->rmi_dev->xport->dev)) 6412b6a321dSAndrew Duggan f01->device_control.ctrl0 |= RMI_SLEEP_MODE_RESERVED1; 6422b6a321dSAndrew Duggan else 6432b6a321dSAndrew Duggan f01->device_control.ctrl0 |= RMI_SLEEP_MODE_SENSOR_SLEEP; 6442b6a321dSAndrew Duggan 6452b6a321dSAndrew Duggan error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 6462b6a321dSAndrew Duggan f01->device_control.ctrl0); 6472b6a321dSAndrew Duggan if (error) { 6482b6a321dSAndrew Duggan dev_err(&fn->dev, "Failed to write sleep mode: %d.\n", error); 6492b6a321dSAndrew Duggan if (f01->old_nosleep) 650e9000b79SNick Dyer f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 6512b6a321dSAndrew Duggan f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 6522b6a321dSAndrew Duggan f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; 6532b6a321dSAndrew Duggan return error; 6542b6a321dSAndrew Duggan } 6552b6a321dSAndrew Duggan 6562b6a321dSAndrew Duggan return 0; 6572b6a321dSAndrew Duggan } 6582b6a321dSAndrew Duggan 6592b6a321dSAndrew Duggan static int rmi_f01_resume(struct rmi_function *fn) 6602b6a321dSAndrew Duggan { 6612b6a321dSAndrew Duggan struct f01_data *f01 = dev_get_drvdata(&fn->dev); 6622b6a321dSAndrew Duggan int error; 6632b6a321dSAndrew Duggan 6642b6a321dSAndrew Duggan if (f01->old_nosleep) 665e9000b79SNick Dyer f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 6662b6a321dSAndrew Duggan 6672b6a321dSAndrew Duggan f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 6682b6a321dSAndrew Duggan f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; 6692b6a321dSAndrew Duggan 6702b6a321dSAndrew Duggan error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 6712b6a321dSAndrew Duggan f01->device_control.ctrl0); 6722b6a321dSAndrew Duggan if (error) { 6732b6a321dSAndrew Duggan dev_err(&fn->dev, 6742b6a321dSAndrew Duggan "Failed to restore normal operation: %d.\n", error); 6752b6a321dSAndrew Duggan return error; 6762b6a321dSAndrew Duggan } 6772b6a321dSAndrew Duggan 6782b6a321dSAndrew Duggan return 0; 6792b6a321dSAndrew Duggan } 6802b6a321dSAndrew Duggan 68124d28e4fSNick Dyer static irqreturn_t rmi_f01_attention(int irq, void *ctx) 6822b6a321dSAndrew Duggan { 68324d28e4fSNick Dyer struct rmi_function *fn = ctx; 6842b6a321dSAndrew Duggan struct rmi_device *rmi_dev = fn->rmi_dev; 6852b6a321dSAndrew Duggan int error; 6862b6a321dSAndrew Duggan u8 device_status; 6872b6a321dSAndrew Duggan 6882b6a321dSAndrew Duggan error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status); 6892b6a321dSAndrew Duggan if (error) { 6902b6a321dSAndrew Duggan dev_err(&fn->dev, 6912b6a321dSAndrew Duggan "Failed to read device status: %d.\n", error); 69224d28e4fSNick Dyer return IRQ_RETVAL(error); 6932b6a321dSAndrew Duggan } 6942b6a321dSAndrew Duggan 69529fd0ec2SNick Dyer if (RMI_F01_STATUS_BOOTLOADER(device_status)) 69629fd0ec2SNick Dyer dev_warn(&fn->dev, 69729fd0ec2SNick Dyer "Device in bootloader mode, please update firmware\n"); 69829fd0ec2SNick Dyer 6992b6a321dSAndrew Duggan if (RMI_F01_STATUS_UNCONFIGURED(device_status)) { 7002b6a321dSAndrew Duggan dev_warn(&fn->dev, "Device reset detected.\n"); 7012b6a321dSAndrew Duggan error = rmi_dev->driver->reset_handler(rmi_dev); 7022b6a321dSAndrew Duggan if (error) { 7032b6a321dSAndrew Duggan dev_err(&fn->dev, "Device reset failed: %d\n", error); 70424d28e4fSNick Dyer return IRQ_RETVAL(error); 7052b6a321dSAndrew Duggan } 7062b6a321dSAndrew Duggan } 7072b6a321dSAndrew Duggan 70824d28e4fSNick Dyer return IRQ_HANDLED; 7092b6a321dSAndrew Duggan } 7102b6a321dSAndrew Duggan 7112b6a321dSAndrew Duggan struct rmi_function_handler rmi_f01_handler = { 7122b6a321dSAndrew Duggan .driver = { 7132b6a321dSAndrew Duggan .name = "rmi4_f01", 7142b6a321dSAndrew Duggan /* 7152b6a321dSAndrew Duggan * Do not allow user unbinding F01 as it is critical 7162b6a321dSAndrew Duggan * function. 7172b6a321dSAndrew Duggan */ 7182b6a321dSAndrew Duggan .suppress_bind_attrs = true, 7192b6a321dSAndrew Duggan }, 7202b6a321dSAndrew Duggan .func = 0x01, 7212b6a321dSAndrew Duggan .probe = rmi_f01_probe, 722060403f3SNick Dyer .remove = rmi_f01_remove, 7232b6a321dSAndrew Duggan .config = rmi_f01_config, 7242b6a321dSAndrew Duggan .attention = rmi_f01_attention, 7252b6a321dSAndrew Duggan .suspend = rmi_f01_suspend, 7262b6a321dSAndrew Duggan .resume = rmi_f01_resume, 7272b6a321dSAndrew Duggan }; 728