162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2011-2016 Synaptics Incorporated 462306a36Sopenharmony_ci * Copyright (c) 2011 Unixphere 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/rmi.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/uaccess.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <asm/unaligned.h> 1362306a36Sopenharmony_ci#include "rmi_driver.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define RMI_PRODUCT_ID_LENGTH 10 1662306a36Sopenharmony_ci#define RMI_PRODUCT_INFO_LENGTH 2 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define RMI_DATE_CODE_LENGTH 3 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define PRODUCT_ID_OFFSET 0x10 2162306a36Sopenharmony_ci#define PRODUCT_INFO_OFFSET 0x1E 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* Force a firmware reset of the sensor */ 2562306a36Sopenharmony_ci#define RMI_F01_CMD_DEVICE_RESET 1 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Various F01_RMI_QueryX bits */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define RMI_F01_QRY1_CUSTOM_MAP BIT(0) 3062306a36Sopenharmony_ci#define RMI_F01_QRY1_NON_COMPLIANT BIT(1) 3162306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_LTS BIT(2) 3262306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_SENSOR_ID BIT(3) 3362306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_CHARGER_INP BIT(4) 3462306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_ADJ_DOZE BIT(5) 3562306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF BIT(6) 3662306a36Sopenharmony_ci#define RMI_F01_QRY1_HAS_QUERY42 BIT(7) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define RMI_F01_QRY5_YEAR_MASK 0x1f 3962306a36Sopenharmony_ci#define RMI_F01_QRY6_MONTH_MASK 0x0f 4062306a36Sopenharmony_ci#define RMI_F01_QRY7_DAY_MASK 0x1f 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define RMI_F01_QRY2_PRODINFO_MASK 0x7f 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct f01_basic_properties { 4762306a36Sopenharmony_ci u8 manufacturer_id; 4862306a36Sopenharmony_ci bool has_lts; 4962306a36Sopenharmony_ci bool has_adjustable_doze; 5062306a36Sopenharmony_ci bool has_adjustable_doze_holdoff; 5162306a36Sopenharmony_ci char dom[11]; /* YYYY/MM/DD + '\0' */ 5262306a36Sopenharmony_ci u8 product_id[RMI_PRODUCT_ID_LENGTH + 1]; 5362306a36Sopenharmony_ci u16 productinfo; 5462306a36Sopenharmony_ci u32 firmware_id; 5562306a36Sopenharmony_ci u32 package_id; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* F01 device status bits */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* Most recent device status event */ 6162306a36Sopenharmony_ci#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f) 6262306a36Sopenharmony_ci/* The device has lost its configuration for some reason. */ 6362306a36Sopenharmony_ci#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80)) 6462306a36Sopenharmony_ci/* The device is in bootloader mode */ 6562306a36Sopenharmony_ci#define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40) 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* Control register bits */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Sleep mode controls power management on the device and affects all 7162306a36Sopenharmony_ci * functions of the device. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define RMI_SLEEP_MODE_NORMAL 0x00 7662306a36Sopenharmony_ci#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01 7762306a36Sopenharmony_ci#define RMI_SLEEP_MODE_RESERVED0 0x02 7862306a36Sopenharmony_ci#define RMI_SLEEP_MODE_RESERVED1 0x03 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * This bit disables whatever sleep mode may be selected by the sleep_mode 8262306a36Sopenharmony_ci * field and forces the device to run at full power without sleeping. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci#define RMI_F01_CTRL0_NOSLEEP_BIT BIT(2) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * When this bit is set, the touch controller employs a noise-filtering 8862306a36Sopenharmony_ci * algorithm designed for use with a connected battery charger. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci#define RMI_F01_CTRL0_CHARGER_BIT BIT(5) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Sets the report rate for the device. The effect of this setting is 9462306a36Sopenharmony_ci * highly product dependent. Check the spec sheet for your particular 9562306a36Sopenharmony_ci * touch sensor. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci#define RMI_F01_CTRL0_REPORTRATE_BIT BIT(6) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Written by the host as an indicator that the device has been 10162306a36Sopenharmony_ci * successfully configured. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci#define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/** 10662306a36Sopenharmony_ci * struct f01_device_control - controls basic sensor functions 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * @ctrl0: see the bit definitions above. 10962306a36Sopenharmony_ci * @doze_interval: controls the interval between checks for finger presence 11062306a36Sopenharmony_ci * when the touch sensor is in doze mode, in units of 10ms. 11162306a36Sopenharmony_ci * @wakeup_threshold: controls the capacitance threshold at which the touch 11262306a36Sopenharmony_ci * sensor will decide to wake up from that low power state. 11362306a36Sopenharmony_ci * @doze_holdoff: controls how long the touch sensor waits after the last 11462306a36Sopenharmony_ci * finger lifts before entering the doze state, in units of 100ms. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistruct f01_device_control { 11762306a36Sopenharmony_ci u8 ctrl0; 11862306a36Sopenharmony_ci u8 doze_interval; 11962306a36Sopenharmony_ci u8 wakeup_threshold; 12062306a36Sopenharmony_ci u8 doze_holdoff; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct f01_data { 12462306a36Sopenharmony_ci struct f01_basic_properties properties; 12562306a36Sopenharmony_ci struct f01_device_control device_control; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci u16 doze_interval_addr; 12862306a36Sopenharmony_ci u16 wakeup_threshold_addr; 12962306a36Sopenharmony_ci u16 doze_holdoff_addr; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci bool suspended; 13262306a36Sopenharmony_ci bool old_nosleep; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci unsigned int num_of_irq_regs; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic int rmi_f01_read_properties(struct rmi_device *rmi_dev, 13862306a36Sopenharmony_ci u16 query_base_addr, 13962306a36Sopenharmony_ci struct f01_basic_properties *props) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci u8 queries[RMI_F01_BASIC_QUERY_LEN]; 14262306a36Sopenharmony_ci int ret; 14362306a36Sopenharmony_ci int query_offset = query_base_addr; 14462306a36Sopenharmony_ci bool has_ds4_queries = false; 14562306a36Sopenharmony_ci bool has_query42 = false; 14662306a36Sopenharmony_ci bool has_sensor_id = false; 14762306a36Sopenharmony_ci bool has_package_id_query = false; 14862306a36Sopenharmony_ci bool has_build_id_query = false; 14962306a36Sopenharmony_ci u16 prod_info_addr; 15062306a36Sopenharmony_ci u8 ds4_query_len; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ret = rmi_read_block(rmi_dev, query_offset, 15362306a36Sopenharmony_ci queries, RMI_F01_BASIC_QUERY_LEN); 15462306a36Sopenharmony_ci if (ret) { 15562306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 15662306a36Sopenharmony_ci "Failed to read device query registers: %d\n", ret); 15762306a36Sopenharmony_ci return ret; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci prod_info_addr = query_offset + 17; 16162306a36Sopenharmony_ci query_offset += RMI_F01_BASIC_QUERY_LEN; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Now parse what we got */ 16462306a36Sopenharmony_ci props->manufacturer_id = queries[0]; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci props->has_lts = queries[1] & RMI_F01_QRY1_HAS_LTS; 16762306a36Sopenharmony_ci props->has_adjustable_doze = 16862306a36Sopenharmony_ci queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE; 16962306a36Sopenharmony_ci props->has_adjustable_doze_holdoff = 17062306a36Sopenharmony_ci queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF; 17162306a36Sopenharmony_ci has_query42 = queries[1] & RMI_F01_QRY1_HAS_QUERY42; 17262306a36Sopenharmony_ci has_sensor_id = queries[1] & RMI_F01_QRY1_HAS_SENSOR_ID; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci snprintf(props->dom, sizeof(props->dom), "20%02d/%02d/%02d", 17562306a36Sopenharmony_ci queries[5] & RMI_F01_QRY5_YEAR_MASK, 17662306a36Sopenharmony_ci queries[6] & RMI_F01_QRY6_MONTH_MASK, 17762306a36Sopenharmony_ci queries[7] & RMI_F01_QRY7_DAY_MASK); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memcpy(props->product_id, &queries[11], 18062306a36Sopenharmony_ci RMI_PRODUCT_ID_LENGTH); 18162306a36Sopenharmony_ci props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0'; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci props->productinfo = 18462306a36Sopenharmony_ci ((queries[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) | 18562306a36Sopenharmony_ci (queries[3] & RMI_F01_QRY2_PRODINFO_MASK); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (has_sensor_id) 18862306a36Sopenharmony_ci query_offset++; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (has_query42) { 19162306a36Sopenharmony_ci ret = rmi_read(rmi_dev, query_offset, queries); 19262306a36Sopenharmony_ci if (ret) { 19362306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 19462306a36Sopenharmony_ci "Failed to read query 42 register: %d\n", ret); 19562306a36Sopenharmony_ci return ret; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci has_ds4_queries = !!(queries[0] & BIT(0)); 19962306a36Sopenharmony_ci query_offset++; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (has_ds4_queries) { 20362306a36Sopenharmony_ci ret = rmi_read(rmi_dev, query_offset, &ds4_query_len); 20462306a36Sopenharmony_ci if (ret) { 20562306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 20662306a36Sopenharmony_ci "Failed to read DS4 queries length: %d\n", ret); 20762306a36Sopenharmony_ci return ret; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci query_offset++; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (ds4_query_len > 0) { 21262306a36Sopenharmony_ci ret = rmi_read(rmi_dev, query_offset, queries); 21362306a36Sopenharmony_ci if (ret) { 21462306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 21562306a36Sopenharmony_ci "Failed to read DS4 queries: %d\n", 21662306a36Sopenharmony_ci ret); 21762306a36Sopenharmony_ci return ret; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci has_package_id_query = !!(queries[0] & BIT(0)); 22162306a36Sopenharmony_ci has_build_id_query = !!(queries[0] & BIT(1)); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (has_package_id_query) { 22562306a36Sopenharmony_ci ret = rmi_read_block(rmi_dev, prod_info_addr, 22662306a36Sopenharmony_ci queries, sizeof(__le64)); 22762306a36Sopenharmony_ci if (ret) { 22862306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 22962306a36Sopenharmony_ci "Failed to read package info: %d\n", 23062306a36Sopenharmony_ci ret); 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci props->package_id = get_unaligned_le64(queries); 23562306a36Sopenharmony_ci prod_info_addr++; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (has_build_id_query) { 23962306a36Sopenharmony_ci ret = rmi_read_block(rmi_dev, prod_info_addr, queries, 24062306a36Sopenharmony_ci 3); 24162306a36Sopenharmony_ci if (ret) { 24262306a36Sopenharmony_ci dev_err(&rmi_dev->dev, 24362306a36Sopenharmony_ci "Failed to read product info: %d\n", 24462306a36Sopenharmony_ci ret); 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci props->firmware_id = queries[1] << 8 | queries[0]; 24962306a36Sopenharmony_ci props->firmware_id += queries[2] * 65536; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciconst char *rmi_f01_get_product_ID(struct rmi_function *fn) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&fn->dev); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return f01->properties.product_id; 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic ssize_t rmi_driver_manufacturer_id_show(struct device *dev, 26462306a36Sopenharmony_ci struct device_attribute *dattr, 26562306a36Sopenharmony_ci char *buf) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct rmi_driver_data *data = dev_get_drvdata(dev); 26862306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", 27162306a36Sopenharmony_ci f01->properties.manufacturer_id); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic DEVICE_ATTR(manufacturer_id, 0444, 27562306a36Sopenharmony_ci rmi_driver_manufacturer_id_show, NULL); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic ssize_t rmi_driver_dom_show(struct device *dev, 27862306a36Sopenharmony_ci struct device_attribute *dattr, char *buf) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct rmi_driver_data *data = dev_get_drvdata(dev); 28162306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.dom); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic DEVICE_ATTR(date_of_manufacture, 0444, rmi_driver_dom_show, NULL); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic ssize_t rmi_driver_product_id_show(struct device *dev, 28962306a36Sopenharmony_ci struct device_attribute *dattr, 29062306a36Sopenharmony_ci char *buf) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct rmi_driver_data *data = dev_get_drvdata(dev); 29362306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s\n", f01->properties.product_id); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic DEVICE_ATTR(product_id, 0444, rmi_driver_product_id_show, NULL); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic ssize_t rmi_driver_firmware_id_show(struct device *dev, 30162306a36Sopenharmony_ci struct device_attribute *dattr, 30262306a36Sopenharmony_ci char *buf) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct rmi_driver_data *data = dev_get_drvdata(dev); 30562306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", f01->properties.firmware_id); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic DEVICE_ATTR(firmware_id, 0444, rmi_driver_firmware_id_show, NULL); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic ssize_t rmi_driver_package_id_show(struct device *dev, 31362306a36Sopenharmony_ci struct device_attribute *dattr, 31462306a36Sopenharmony_ci char *buf) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct rmi_driver_data *data = dev_get_drvdata(dev); 31762306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&data->f01_container->dev); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci u32 package_id = f01->properties.package_id; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%04x.%04x\n", 32262306a36Sopenharmony_ci package_id & 0xffff, (package_id >> 16) & 0xffff); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic DEVICE_ATTR(package_id, 0444, rmi_driver_package_id_show, NULL); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic struct attribute *rmi_f01_attrs[] = { 32862306a36Sopenharmony_ci &dev_attr_manufacturer_id.attr, 32962306a36Sopenharmony_ci &dev_attr_date_of_manufacture.attr, 33062306a36Sopenharmony_ci &dev_attr_product_id.attr, 33162306a36Sopenharmony_ci &dev_attr_firmware_id.attr, 33262306a36Sopenharmony_ci &dev_attr_package_id.attr, 33362306a36Sopenharmony_ci NULL 33462306a36Sopenharmony_ci}; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic const struct attribute_group rmi_f01_attr_group = { 33762306a36Sopenharmony_ci .attrs = rmi_f01_attrs, 33862306a36Sopenharmony_ci}; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci#ifdef CONFIG_OF 34162306a36Sopenharmony_cistatic int rmi_f01_of_probe(struct device *dev, 34262306a36Sopenharmony_ci struct rmi_device_platform_data *pdata) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int retval; 34562306a36Sopenharmony_ci u32 val; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, 34862306a36Sopenharmony_ci (u32 *)&pdata->power_management.nosleep, 34962306a36Sopenharmony_ci "syna,nosleep-mode", 1); 35062306a36Sopenharmony_ci if (retval) 35162306a36Sopenharmony_ci return retval; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, 35462306a36Sopenharmony_ci "syna,wakeup-threshold", 1); 35562306a36Sopenharmony_ci if (retval) 35662306a36Sopenharmony_ci return retval; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci pdata->power_management.wakeup_threshold = val; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, 36162306a36Sopenharmony_ci "syna,doze-holdoff-ms", 1); 36262306a36Sopenharmony_ci if (retval) 36362306a36Sopenharmony_ci return retval; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci pdata->power_management.doze_holdoff = val * 100; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, 36862306a36Sopenharmony_ci "syna,doze-interval-ms", 1); 36962306a36Sopenharmony_ci if (retval) 37062306a36Sopenharmony_ci return retval; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci pdata->power_management.doze_interval = val / 10; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci#else 37762306a36Sopenharmony_cistatic inline int rmi_f01_of_probe(struct device *dev, 37862306a36Sopenharmony_ci struct rmi_device_platform_data *pdata) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci return -ENODEV; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci#endif 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int rmi_f01_probe(struct rmi_function *fn) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 38762306a36Sopenharmony_ci struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev); 38862306a36Sopenharmony_ci struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); 38962306a36Sopenharmony_ci struct f01_data *f01; 39062306a36Sopenharmony_ci int error; 39162306a36Sopenharmony_ci u16 ctrl_base_addr = fn->fd.control_base_addr; 39262306a36Sopenharmony_ci u8 device_status; 39362306a36Sopenharmony_ci u8 temp; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (fn->dev.of_node) { 39662306a36Sopenharmony_ci error = rmi_f01_of_probe(&fn->dev, pdata); 39762306a36Sopenharmony_ci if (error) 39862306a36Sopenharmony_ci return error; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci f01 = devm_kzalloc(&fn->dev, sizeof(struct f01_data), GFP_KERNEL); 40262306a36Sopenharmony_ci if (!f01) 40362306a36Sopenharmony_ci return -ENOMEM; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci f01->num_of_irq_regs = driver_data->num_of_irq_regs; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* 40862306a36Sopenharmony_ci * Set the configured bit and (optionally) other important stuff 40962306a36Sopenharmony_ci * in the device control register. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci error = rmi_read(rmi_dev, fn->fd.control_base_addr, 41362306a36Sopenharmony_ci &f01->device_control.ctrl0); 41462306a36Sopenharmony_ci if (error) { 41562306a36Sopenharmony_ci dev_err(&fn->dev, "Failed to read F01 control: %d\n", error); 41662306a36Sopenharmony_ci return error; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci switch (pdata->power_management.nosleep) { 42062306a36Sopenharmony_ci case RMI_REG_STATE_DEFAULT: 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case RMI_REG_STATE_OFF: 42362306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case RMI_REG_STATE_ON: 42662306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* 43162306a36Sopenharmony_ci * Sleep mode might be set as a hangover from a system crash or 43262306a36Sopenharmony_ci * reboot without power cycle. If so, clear it so the sensor 43362306a36Sopenharmony_ci * is certain to function. 43462306a36Sopenharmony_ci */ 43562306a36Sopenharmony_ci if ((f01->device_control.ctrl0 & RMI_F01_CTRL0_SLEEP_MODE_MASK) != 43662306a36Sopenharmony_ci RMI_SLEEP_MODE_NORMAL) { 43762306a36Sopenharmony_ci dev_warn(&fn->dev, 43862306a36Sopenharmony_ci "WARNING: Non-zero sleep mode found. Clearing...\n"); 43962306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_F01_CTRL0_CONFIGURED_BIT; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci error = rmi_write(rmi_dev, fn->fd.control_base_addr, 44562306a36Sopenharmony_ci f01->device_control.ctrl0); 44662306a36Sopenharmony_ci if (error) { 44762306a36Sopenharmony_ci dev_err(&fn->dev, "Failed to write F01 control: %d\n", error); 44862306a36Sopenharmony_ci return error; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* Dummy read in order to clear irqs */ 45262306a36Sopenharmony_ci error = rmi_read(rmi_dev, fn->fd.data_base_addr + 1, &temp); 45362306a36Sopenharmony_ci if (error < 0) { 45462306a36Sopenharmony_ci dev_err(&fn->dev, "Failed to read Interrupt Status.\n"); 45562306a36Sopenharmony_ci return error; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci error = rmi_f01_read_properties(rmi_dev, fn->fd.query_base_addr, 45962306a36Sopenharmony_ci &f01->properties); 46062306a36Sopenharmony_ci if (error < 0) { 46162306a36Sopenharmony_ci dev_err(&fn->dev, "Failed to read F01 properties.\n"); 46262306a36Sopenharmony_ci return error; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s, fw id: %d\n", 46662306a36Sopenharmony_ci f01->properties.manufacturer_id == 1 ? "Synaptics" : "unknown", 46762306a36Sopenharmony_ci f01->properties.product_id, f01->properties.firmware_id); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Advance to interrupt control registers, then skip over them. */ 47062306a36Sopenharmony_ci ctrl_base_addr++; 47162306a36Sopenharmony_ci ctrl_base_addr += f01->num_of_irq_regs; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* read control register */ 47462306a36Sopenharmony_ci if (f01->properties.has_adjustable_doze) { 47562306a36Sopenharmony_ci f01->doze_interval_addr = ctrl_base_addr; 47662306a36Sopenharmony_ci ctrl_base_addr++; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (pdata->power_management.doze_interval) { 47962306a36Sopenharmony_ci f01->device_control.doze_interval = 48062306a36Sopenharmony_ci pdata->power_management.doze_interval; 48162306a36Sopenharmony_ci error = rmi_write(rmi_dev, f01->doze_interval_addr, 48262306a36Sopenharmony_ci f01->device_control.doze_interval); 48362306a36Sopenharmony_ci if (error) { 48462306a36Sopenharmony_ci dev_err(&fn->dev, 48562306a36Sopenharmony_ci "Failed to configure F01 doze interval register: %d\n", 48662306a36Sopenharmony_ci error); 48762306a36Sopenharmony_ci return error; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci } else { 49062306a36Sopenharmony_ci error = rmi_read(rmi_dev, f01->doze_interval_addr, 49162306a36Sopenharmony_ci &f01->device_control.doze_interval); 49262306a36Sopenharmony_ci if (error) { 49362306a36Sopenharmony_ci dev_err(&fn->dev, 49462306a36Sopenharmony_ci "Failed to read F01 doze interval register: %d\n", 49562306a36Sopenharmony_ci error); 49662306a36Sopenharmony_ci return error; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci f01->wakeup_threshold_addr = ctrl_base_addr; 50162306a36Sopenharmony_ci ctrl_base_addr++; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (pdata->power_management.wakeup_threshold) { 50462306a36Sopenharmony_ci f01->device_control.wakeup_threshold = 50562306a36Sopenharmony_ci pdata->power_management.wakeup_threshold; 50662306a36Sopenharmony_ci error = rmi_write(rmi_dev, f01->wakeup_threshold_addr, 50762306a36Sopenharmony_ci f01->device_control.wakeup_threshold); 50862306a36Sopenharmony_ci if (error) { 50962306a36Sopenharmony_ci dev_err(&fn->dev, 51062306a36Sopenharmony_ci "Failed to configure F01 wakeup threshold register: %d\n", 51162306a36Sopenharmony_ci error); 51262306a36Sopenharmony_ci return error; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci } else { 51562306a36Sopenharmony_ci error = rmi_read(rmi_dev, f01->wakeup_threshold_addr, 51662306a36Sopenharmony_ci &f01->device_control.wakeup_threshold); 51762306a36Sopenharmony_ci if (error < 0) { 51862306a36Sopenharmony_ci dev_err(&fn->dev, 51962306a36Sopenharmony_ci "Failed to read F01 wakeup threshold register: %d\n", 52062306a36Sopenharmony_ci error); 52162306a36Sopenharmony_ci return error; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (f01->properties.has_lts) 52762306a36Sopenharmony_ci ctrl_base_addr++; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (f01->properties.has_adjustable_doze_holdoff) { 53062306a36Sopenharmony_ci f01->doze_holdoff_addr = ctrl_base_addr; 53162306a36Sopenharmony_ci ctrl_base_addr++; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (pdata->power_management.doze_holdoff) { 53462306a36Sopenharmony_ci f01->device_control.doze_holdoff = 53562306a36Sopenharmony_ci pdata->power_management.doze_holdoff; 53662306a36Sopenharmony_ci error = rmi_write(rmi_dev, f01->doze_holdoff_addr, 53762306a36Sopenharmony_ci f01->device_control.doze_holdoff); 53862306a36Sopenharmony_ci if (error) { 53962306a36Sopenharmony_ci dev_err(&fn->dev, 54062306a36Sopenharmony_ci "Failed to configure F01 doze holdoff register: %d\n", 54162306a36Sopenharmony_ci error); 54262306a36Sopenharmony_ci return error; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } else { 54562306a36Sopenharmony_ci error = rmi_read(rmi_dev, f01->doze_holdoff_addr, 54662306a36Sopenharmony_ci &f01->device_control.doze_holdoff); 54762306a36Sopenharmony_ci if (error) { 54862306a36Sopenharmony_ci dev_err(&fn->dev, 54962306a36Sopenharmony_ci "Failed to read F01 doze holdoff register: %d\n", 55062306a36Sopenharmony_ci error); 55162306a36Sopenharmony_ci return error; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status); 55762306a36Sopenharmony_ci if (error < 0) { 55862306a36Sopenharmony_ci dev_err(&fn->dev, 55962306a36Sopenharmony_ci "Failed to read device status: %d\n", error); 56062306a36Sopenharmony_ci return error; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (RMI_F01_STATUS_UNCONFIGURED(device_status)) { 56462306a36Sopenharmony_ci dev_err(&fn->dev, 56562306a36Sopenharmony_ci "Device was reset during configuration process, status: %#02x!\n", 56662306a36Sopenharmony_ci RMI_F01_STATUS_CODE(device_status)); 56762306a36Sopenharmony_ci return -EINVAL; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci dev_set_drvdata(&fn->dev, f01); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci error = sysfs_create_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group); 57362306a36Sopenharmony_ci if (error) 57462306a36Sopenharmony_ci dev_warn(&fn->dev, "Failed to create sysfs group: %d\n", error); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void rmi_f01_remove(struct rmi_function *fn) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci /* Note that the bus device is used, not the F01 device */ 58262306a36Sopenharmony_ci sysfs_remove_group(&fn->rmi_dev->dev.kobj, &rmi_f01_attr_group); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int rmi_f01_config(struct rmi_function *fn) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&fn->dev); 58862306a36Sopenharmony_ci int error; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 59162306a36Sopenharmony_ci f01->device_control.ctrl0); 59262306a36Sopenharmony_ci if (error) { 59362306a36Sopenharmony_ci dev_err(&fn->dev, 59462306a36Sopenharmony_ci "Failed to write device_control register: %d\n", error); 59562306a36Sopenharmony_ci return error; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci if (f01->properties.has_adjustable_doze) { 59962306a36Sopenharmony_ci error = rmi_write(fn->rmi_dev, f01->doze_interval_addr, 60062306a36Sopenharmony_ci f01->device_control.doze_interval); 60162306a36Sopenharmony_ci if (error) { 60262306a36Sopenharmony_ci dev_err(&fn->dev, 60362306a36Sopenharmony_ci "Failed to write doze interval: %d\n", error); 60462306a36Sopenharmony_ci return error; 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci error = rmi_write_block(fn->rmi_dev, 60862306a36Sopenharmony_ci f01->wakeup_threshold_addr, 60962306a36Sopenharmony_ci &f01->device_control.wakeup_threshold, 61062306a36Sopenharmony_ci sizeof(u8)); 61162306a36Sopenharmony_ci if (error) { 61262306a36Sopenharmony_ci dev_err(&fn->dev, 61362306a36Sopenharmony_ci "Failed to write wakeup threshold: %d\n", 61462306a36Sopenharmony_ci error); 61562306a36Sopenharmony_ci return error; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (f01->properties.has_adjustable_doze_holdoff) { 62062306a36Sopenharmony_ci error = rmi_write(fn->rmi_dev, f01->doze_holdoff_addr, 62162306a36Sopenharmony_ci f01->device_control.doze_holdoff); 62262306a36Sopenharmony_ci if (error) { 62362306a36Sopenharmony_ci dev_err(&fn->dev, 62462306a36Sopenharmony_ci "Failed to write doze holdoff: %d\n", error); 62562306a36Sopenharmony_ci return error; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci return 0; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int rmi_f01_suspend(struct rmi_function *fn) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&fn->dev); 63562306a36Sopenharmony_ci int error; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci f01->old_nosleep = 63862306a36Sopenharmony_ci f01->device_control.ctrl0 & RMI_F01_CTRL0_NOSLEEP_BIT; 63962306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 64262306a36Sopenharmony_ci if (device_may_wakeup(fn->rmi_dev->xport->dev)) 64362306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_SLEEP_MODE_RESERVED1; 64462306a36Sopenharmony_ci else 64562306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_SLEEP_MODE_SENSOR_SLEEP; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 64862306a36Sopenharmony_ci f01->device_control.ctrl0); 64962306a36Sopenharmony_ci if (error) { 65062306a36Sopenharmony_ci dev_err(&fn->dev, "Failed to write sleep mode: %d.\n", error); 65162306a36Sopenharmony_ci if (f01->old_nosleep) 65262306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 65362306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 65462306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; 65562306a36Sopenharmony_ci return error; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci return 0; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int rmi_f01_resume(struct rmi_function *fn) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct f01_data *f01 = dev_get_drvdata(&fn->dev); 66462306a36Sopenharmony_ci int error; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (f01->old_nosleep) 66762306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK; 67062306a36Sopenharmony_ci f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr, 67362306a36Sopenharmony_ci f01->device_control.ctrl0); 67462306a36Sopenharmony_ci if (error) { 67562306a36Sopenharmony_ci dev_err(&fn->dev, 67662306a36Sopenharmony_ci "Failed to restore normal operation: %d.\n", error); 67762306a36Sopenharmony_ci return error; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic irqreturn_t rmi_f01_attention(int irq, void *ctx) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct rmi_function *fn = ctx; 68662306a36Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 68762306a36Sopenharmony_ci int error; 68862306a36Sopenharmony_ci u8 device_status; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status); 69162306a36Sopenharmony_ci if (error) { 69262306a36Sopenharmony_ci dev_err(&fn->dev, 69362306a36Sopenharmony_ci "Failed to read device status: %d.\n", error); 69462306a36Sopenharmony_ci return IRQ_RETVAL(error); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (RMI_F01_STATUS_BOOTLOADER(device_status)) 69862306a36Sopenharmony_ci dev_warn(&fn->dev, 69962306a36Sopenharmony_ci "Device in bootloader mode, please update firmware\n"); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (RMI_F01_STATUS_UNCONFIGURED(device_status)) { 70262306a36Sopenharmony_ci dev_warn(&fn->dev, "Device reset detected.\n"); 70362306a36Sopenharmony_ci error = rmi_dev->driver->reset_handler(rmi_dev); 70462306a36Sopenharmony_ci if (error) { 70562306a36Sopenharmony_ci dev_err(&fn->dev, "Device reset failed: %d\n", error); 70662306a36Sopenharmony_ci return IRQ_RETVAL(error); 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci return IRQ_HANDLED; 71162306a36Sopenharmony_ci} 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistruct rmi_function_handler rmi_f01_handler = { 71462306a36Sopenharmony_ci .driver = { 71562306a36Sopenharmony_ci .name = "rmi4_f01", 71662306a36Sopenharmony_ci /* 71762306a36Sopenharmony_ci * Do not allow user unbinding F01 as it is critical 71862306a36Sopenharmony_ci * function. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ci .suppress_bind_attrs = true, 72162306a36Sopenharmony_ci }, 72262306a36Sopenharmony_ci .func = 0x01, 72362306a36Sopenharmony_ci .probe = rmi_f01_probe, 72462306a36Sopenharmony_ci .remove = rmi_f01_remove, 72562306a36Sopenharmony_ci .config = rmi_f01_config, 72662306a36Sopenharmony_ci .attention = rmi_f01_attention, 72762306a36Sopenharmony_ci .suspend = rmi_f01_suspend, 72862306a36Sopenharmony_ci .resume = rmi_f01_resume, 72962306a36Sopenharmony_ci}; 730