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