18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2016 Synaptics Incorporated 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kernel.h> 78c2ecf20Sopenharmony_ci#include <linux/rmi.h> 88c2ecf20Sopenharmony_ci#include <linux/input.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include "rmi_driver.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#define RMI_F30_QUERY_SIZE 2 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* Defs for Query 0 */ 158c2ecf20Sopenharmony_ci#define RMI_F30_EXTENDED_PATTERNS 0x01 168c2ecf20Sopenharmony_ci#define RMI_F30_HAS_MAPPABLE_BUTTONS BIT(1) 178c2ecf20Sopenharmony_ci#define RMI_F30_HAS_LED BIT(2) 188c2ecf20Sopenharmony_ci#define RMI_F30_HAS_GPIO BIT(3) 198c2ecf20Sopenharmony_ci#define RMI_F30_HAS_HAPTIC BIT(4) 208c2ecf20Sopenharmony_ci#define RMI_F30_HAS_GPIO_DRV_CTL BIT(5) 218c2ecf20Sopenharmony_ci#define RMI_F30_HAS_MECH_MOUSE_BTNS BIT(6) 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Defs for Query 1 */ 248c2ecf20Sopenharmony_ci#define RMI_F30_GPIO_LED_COUNT 0x1F 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Defs for Control Registers */ 278c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_GPIO_DEBOUNCE 0x01 288c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_HALT BIT(4) 298c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_1_HALTED BIT(5) 308c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_REGS 32 338c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_BYTES DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8) 348c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_MAX_REG_BLOCKS 11 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES \ 378c2ecf20Sopenharmony_ci + 1 \ 388c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_BYTES \ 398c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_BYTES \ 408c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_BYTES \ 418c2ecf20Sopenharmony_ci + 6 \ 428c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_REGS \ 438c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_REGS \ 448c2ecf20Sopenharmony_ci + RMI_F30_CTRL_MAX_BYTES \ 458c2ecf20Sopenharmony_ci + 1 \ 468c2ecf20Sopenharmony_ci + 1) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_START 3 498c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_END 6 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct rmi_f30_ctrl_data { 528c2ecf20Sopenharmony_ci int address; 538c2ecf20Sopenharmony_ci int length; 548c2ecf20Sopenharmony_ci u8 *regs; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct f30_data { 588c2ecf20Sopenharmony_ci /* Query Data */ 598c2ecf20Sopenharmony_ci bool has_extended_pattern; 608c2ecf20Sopenharmony_ci bool has_mappable_buttons; 618c2ecf20Sopenharmony_ci bool has_led; 628c2ecf20Sopenharmony_ci bool has_gpio; 638c2ecf20Sopenharmony_ci bool has_haptic; 648c2ecf20Sopenharmony_ci bool has_gpio_driver_control; 658c2ecf20Sopenharmony_ci bool has_mech_mouse_btns; 668c2ecf20Sopenharmony_ci u8 gpioled_count; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci u8 register_count; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Control Register Data */ 718c2ecf20Sopenharmony_ci struct rmi_f30_ctrl_data ctrl[RMI_F30_CTRL_MAX_REG_BLOCKS]; 728c2ecf20Sopenharmony_ci u8 ctrl_regs[RMI_F30_CTRL_REGS_MAX_SIZE]; 738c2ecf20Sopenharmony_ci u32 ctrl_regs_size; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci u8 data_regs[RMI_F30_CTRL_MAX_BYTES]; 768c2ecf20Sopenharmony_ci u16 *gpioled_key_map; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci struct input_dev *input; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci struct rmi_function *f03; 818c2ecf20Sopenharmony_ci bool trackstick_buttons; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int rmi_f30_read_control_parameters(struct rmi_function *fn, 858c2ecf20Sopenharmony_ci struct f30_data *f30) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int error; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr, 908c2ecf20Sopenharmony_ci f30->ctrl_regs, f30->ctrl_regs_size); 918c2ecf20Sopenharmony_ci if (error) { 928c2ecf20Sopenharmony_ci dev_err(&fn->dev, 938c2ecf20Sopenharmony_ci "%s: Could not read control registers at 0x%x: %d\n", 948c2ecf20Sopenharmony_ci __func__, fn->fd.control_base_addr, error); 958c2ecf20Sopenharmony_ci return error; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic void rmi_f30_report_button(struct rmi_function *fn, 1028c2ecf20Sopenharmony_ci struct f30_data *f30, unsigned int button) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci unsigned int reg_num = button >> 3; 1058c2ecf20Sopenharmony_ci unsigned int bit_num = button & 0x07; 1068c2ecf20Sopenharmony_ci u16 key_code = f30->gpioled_key_map[button]; 1078c2ecf20Sopenharmony_ci bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num)); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (f30->trackstick_buttons && 1108c2ecf20Sopenharmony_ci button >= TRACKSTICK_RANGE_START && 1118c2ecf20Sopenharmony_ci button <= TRACKSTICK_RANGE_END) { 1128c2ecf20Sopenharmony_ci rmi_f03_overwrite_button(f30->f03, key_code, key_down); 1138c2ecf20Sopenharmony_ci } else { 1148c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, 1158c2ecf20Sopenharmony_ci "%s: call input report key (0x%04x) value (0x%02x)", 1168c2ecf20Sopenharmony_ci __func__, key_code, key_down); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci input_report_key(f30->input, key_code, key_down); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic irqreturn_t rmi_f30_attention(int irq, void *ctx) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct rmi_function *fn = ctx; 1258c2ecf20Sopenharmony_ci struct f30_data *f30 = dev_get_drvdata(&fn->dev); 1268c2ecf20Sopenharmony_ci struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); 1278c2ecf20Sopenharmony_ci int error; 1288c2ecf20Sopenharmony_ci int i; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* Read the gpi led data. */ 1318c2ecf20Sopenharmony_ci if (drvdata->attn_data.data) { 1328c2ecf20Sopenharmony_ci if (drvdata->attn_data.size < f30->register_count) { 1338c2ecf20Sopenharmony_ci dev_warn(&fn->dev, 1348c2ecf20Sopenharmony_ci "F30 interrupted, but data is missing\n"); 1358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci memcpy(f30->data_regs, drvdata->attn_data.data, 1388c2ecf20Sopenharmony_ci f30->register_count); 1398c2ecf20Sopenharmony_ci drvdata->attn_data.data += f30->register_count; 1408c2ecf20Sopenharmony_ci drvdata->attn_data.size -= f30->register_count; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, 1438c2ecf20Sopenharmony_ci f30->data_regs, f30->register_count); 1448c2ecf20Sopenharmony_ci if (error) { 1458c2ecf20Sopenharmony_ci dev_err(&fn->dev, 1468c2ecf20Sopenharmony_ci "%s: Failed to read F30 data registers: %d\n", 1478c2ecf20Sopenharmony_ci __func__, error); 1488c2ecf20Sopenharmony_ci return IRQ_RETVAL(error); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (f30->has_gpio) { 1538c2ecf20Sopenharmony_ci for (i = 0; i < f30->gpioled_count; i++) 1548c2ecf20Sopenharmony_ci if (f30->gpioled_key_map[i] != KEY_RESERVED) 1558c2ecf20Sopenharmony_ci rmi_f30_report_button(fn, f30, i); 1568c2ecf20Sopenharmony_ci if (f30->trackstick_buttons) 1578c2ecf20Sopenharmony_ci rmi_f03_commit_buttons(f30->f03); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int rmi_f30_config(struct rmi_function *fn) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct f30_data *f30 = dev_get_drvdata(&fn->dev); 1668c2ecf20Sopenharmony_ci struct rmi_driver *drv = fn->rmi_dev->driver; 1678c2ecf20Sopenharmony_ci const struct rmi_device_platform_data *pdata = 1688c2ecf20Sopenharmony_ci rmi_get_platform_data(fn->rmi_dev); 1698c2ecf20Sopenharmony_ci int error; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* can happen if gpio_data.disable is set */ 1728c2ecf20Sopenharmony_ci if (!f30) 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (pdata->gpio_data.trackstick_buttons) { 1768c2ecf20Sopenharmony_ci /* Try [re-]establish link to F03. */ 1778c2ecf20Sopenharmony_ci f30->f03 = rmi_find_function(fn->rmi_dev, 0x03); 1788c2ecf20Sopenharmony_ci f30->trackstick_buttons = f30->f03 != NULL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (pdata->gpio_data.disable) { 1828c2ecf20Sopenharmony_ci drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask); 1838c2ecf20Sopenharmony_ci } else { 1848c2ecf20Sopenharmony_ci /* Write Control Register values back to device */ 1858c2ecf20Sopenharmony_ci error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr, 1868c2ecf20Sopenharmony_ci f30->ctrl_regs, f30->ctrl_regs_size); 1878c2ecf20Sopenharmony_ci if (error) { 1888c2ecf20Sopenharmony_ci dev_err(&fn->dev, 1898c2ecf20Sopenharmony_ci "%s: Could not write control registers at 0x%x: %d\n", 1908c2ecf20Sopenharmony_ci __func__, fn->fd.control_base_addr, error); 1918c2ecf20Sopenharmony_ci return error; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl, 2018c2ecf20Sopenharmony_ci int *ctrl_addr, int len, u8 **reg) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci ctrl->address = *ctrl_addr; 2048c2ecf20Sopenharmony_ci ctrl->length = len; 2058c2ecf20Sopenharmony_ci ctrl->regs = *reg; 2068c2ecf20Sopenharmony_ci *ctrl_addr += len; 2078c2ecf20Sopenharmony_ci *reg += len; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic bool rmi_f30_is_valid_button(int button, struct rmi_f30_ctrl_data *ctrl) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci int byte_position = button >> 3; 2138c2ecf20Sopenharmony_ci int bit_position = button & 0x07; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* 2168c2ecf20Sopenharmony_ci * ctrl2 -> dir == 0 -> input mode 2178c2ecf20Sopenharmony_ci * ctrl3 -> data == 1 -> actual button 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci return !(ctrl[2].regs[byte_position] & BIT(bit_position)) && 2208c2ecf20Sopenharmony_ci (ctrl[3].regs[byte_position] & BIT(bit_position)); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int rmi_f30_map_gpios(struct rmi_function *fn, 2248c2ecf20Sopenharmony_ci struct f30_data *f30) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci const struct rmi_device_platform_data *pdata = 2278c2ecf20Sopenharmony_ci rmi_get_platform_data(fn->rmi_dev); 2288c2ecf20Sopenharmony_ci struct input_dev *input = f30->input; 2298c2ecf20Sopenharmony_ci unsigned int button = BTN_LEFT; 2308c2ecf20Sopenharmony_ci unsigned int trackstick_button = BTN_LEFT; 2318c2ecf20Sopenharmony_ci bool button_mapped = false; 2328c2ecf20Sopenharmony_ci int i; 2338c2ecf20Sopenharmony_ci int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci f30->gpioled_key_map = devm_kcalloc(&fn->dev, 2368c2ecf20Sopenharmony_ci button_count, 2378c2ecf20Sopenharmony_ci sizeof(f30->gpioled_key_map[0]), 2388c2ecf20Sopenharmony_ci GFP_KERNEL); 2398c2ecf20Sopenharmony_ci if (!f30->gpioled_key_map) { 2408c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n"); 2418c2ecf20Sopenharmony_ci return -ENOMEM; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci for (i = 0; i < button_count; i++) { 2458c2ecf20Sopenharmony_ci if (!rmi_f30_is_valid_button(i, f30->ctrl)) 2468c2ecf20Sopenharmony_ci continue; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (pdata->gpio_data.trackstick_buttons && 2498c2ecf20Sopenharmony_ci i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) { 2508c2ecf20Sopenharmony_ci f30->gpioled_key_map[i] = trackstick_button++; 2518c2ecf20Sopenharmony_ci } else if (!pdata->gpio_data.buttonpad || !button_mapped) { 2528c2ecf20Sopenharmony_ci f30->gpioled_key_map[i] = button; 2538c2ecf20Sopenharmony_ci input_set_capability(input, EV_KEY, button++); 2548c2ecf20Sopenharmony_ci button_mapped = true; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci input->keycode = f30->gpioled_key_map; 2598c2ecf20Sopenharmony_ci input->keycodesize = sizeof(f30->gpioled_key_map[0]); 2608c2ecf20Sopenharmony_ci input->keycodemax = f30->gpioled_count; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * Buttonpad could be also inferred from f30->has_mech_mouse_btns, 2648c2ecf20Sopenharmony_ci * but I am not sure, so use only the pdata info and the number of 2658c2ecf20Sopenharmony_ci * mapped buttons. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1)) 2688c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int rmi_f30_initialize(struct rmi_function *fn, struct f30_data *f30) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci u8 *ctrl_reg = f30->ctrl_regs; 2768c2ecf20Sopenharmony_ci int control_address = fn->fd.control_base_addr; 2778c2ecf20Sopenharmony_ci u8 buf[RMI_F30_QUERY_SIZE]; 2788c2ecf20Sopenharmony_ci int error; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, 2818c2ecf20Sopenharmony_ci buf, RMI_F30_QUERY_SIZE); 2828c2ecf20Sopenharmony_ci if (error) { 2838c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to read query register\n"); 2848c2ecf20Sopenharmony_ci return error; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci f30->has_extended_pattern = buf[0] & RMI_F30_EXTENDED_PATTERNS; 2888c2ecf20Sopenharmony_ci f30->has_mappable_buttons = buf[0] & RMI_F30_HAS_MAPPABLE_BUTTONS; 2898c2ecf20Sopenharmony_ci f30->has_led = buf[0] & RMI_F30_HAS_LED; 2908c2ecf20Sopenharmony_ci f30->has_gpio = buf[0] & RMI_F30_HAS_GPIO; 2918c2ecf20Sopenharmony_ci f30->has_haptic = buf[0] & RMI_F30_HAS_HAPTIC; 2928c2ecf20Sopenharmony_ci f30->has_gpio_driver_control = buf[0] & RMI_F30_HAS_GPIO_DRV_CTL; 2938c2ecf20Sopenharmony_ci f30->has_mech_mouse_btns = buf[0] & RMI_F30_HAS_MECH_MOUSE_BTNS; 2948c2ecf20Sopenharmony_ci f30->gpioled_count = buf[1] & RMI_F30_GPIO_LED_COUNT; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci f30->register_count = DIV_ROUND_UP(f30->gpioled_count, 8); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (f30->has_gpio && f30->has_led) 2998c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address, 3008c2ecf20Sopenharmony_ci f30->register_count, &ctrl_reg); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address, 3038c2ecf20Sopenharmony_ci sizeof(u8), &ctrl_reg); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (f30->has_gpio) { 3068c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address, 3078c2ecf20Sopenharmony_ci f30->register_count, &ctrl_reg); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address, 3108c2ecf20Sopenharmony_ci f30->register_count, &ctrl_reg); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (f30->has_led) { 3148c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address, 3158c2ecf20Sopenharmony_ci f30->register_count, &ctrl_reg); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address, 3188c2ecf20Sopenharmony_ci f30->has_extended_pattern ? 6 : 2, 3198c2ecf20Sopenharmony_ci &ctrl_reg); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (f30->has_led || f30->has_gpio_driver_control) { 3238c2ecf20Sopenharmony_ci /* control 6 uses a byte per gpio/led */ 3248c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address, 3258c2ecf20Sopenharmony_ci f30->gpioled_count, &ctrl_reg); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (f30->has_mappable_buttons) { 3298c2ecf20Sopenharmony_ci /* control 7 uses a byte per gpio/led */ 3308c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address, 3318c2ecf20Sopenharmony_ci f30->gpioled_count, &ctrl_reg); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (f30->has_haptic) { 3358c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address, 3368c2ecf20Sopenharmony_ci f30->register_count, &ctrl_reg); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address, 3398c2ecf20Sopenharmony_ci sizeof(u8), &ctrl_reg); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (f30->has_mech_mouse_btns) 3438c2ecf20Sopenharmony_ci rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address, 3448c2ecf20Sopenharmony_ci sizeof(u8), &ctrl_reg); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci f30->ctrl_regs_size = ctrl_reg - 3478c2ecf20Sopenharmony_ci f30->ctrl_regs ?: RMI_F30_CTRL_REGS_MAX_SIZE; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci error = rmi_f30_read_control_parameters(fn, f30); 3508c2ecf20Sopenharmony_ci if (error) { 3518c2ecf20Sopenharmony_ci dev_err(&fn->dev, 3528c2ecf20Sopenharmony_ci "Failed to initialize F30 control params: %d\n", 3538c2ecf20Sopenharmony_ci error); 3548c2ecf20Sopenharmony_ci return error; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (f30->has_gpio) { 3588c2ecf20Sopenharmony_ci error = rmi_f30_map_gpios(fn, f30); 3598c2ecf20Sopenharmony_ci if (error) 3608c2ecf20Sopenharmony_ci return error; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int rmi_f30_probe(struct rmi_function *fn) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 3698c2ecf20Sopenharmony_ci const struct rmi_device_platform_data *pdata = 3708c2ecf20Sopenharmony_ci rmi_get_platform_data(rmi_dev); 3718c2ecf20Sopenharmony_ci struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 3728c2ecf20Sopenharmony_ci struct f30_data *f30; 3738c2ecf20Sopenharmony_ci int error; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (pdata->gpio_data.disable) 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (!drv_data->input) { 3798c2ecf20Sopenharmony_ci dev_info(&fn->dev, "F30: no input device found, ignoring\n"); 3808c2ecf20Sopenharmony_ci return -ENXIO; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci f30 = devm_kzalloc(&fn->dev, sizeof(*f30), GFP_KERNEL); 3848c2ecf20Sopenharmony_ci if (!f30) 3858c2ecf20Sopenharmony_ci return -ENOMEM; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci f30->input = drv_data->input; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci error = rmi_f30_initialize(fn, f30); 3908c2ecf20Sopenharmony_ci if (error) 3918c2ecf20Sopenharmony_ci return error; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci dev_set_drvdata(&fn->dev, f30); 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistruct rmi_function_handler rmi_f30_handler = { 3988c2ecf20Sopenharmony_ci .driver = { 3998c2ecf20Sopenharmony_ci .name = "rmi4_f30", 4008c2ecf20Sopenharmony_ci }, 4018c2ecf20Sopenharmony_ci .func = 0x30, 4028c2ecf20Sopenharmony_ci .probe = rmi_f30_probe, 4038c2ecf20Sopenharmony_ci .config = rmi_f30_config, 4048c2ecf20Sopenharmony_ci .attention = rmi_f30_attention, 4058c2ecf20Sopenharmony_ci}; 406