18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2020 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_F3A_MAX_GPIO_COUNT 128 138c2ecf20Sopenharmony_ci#define RMI_F3A_MAX_REG_SIZE DIV_ROUND_UP(RMI_F3A_MAX_GPIO_COUNT, 8) 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* Defs for Query 0 */ 168c2ecf20Sopenharmony_ci#define RMI_F3A_GPIO_COUNT 0x7F 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define RMI_F3A_DATA_REGS_MAX_SIZE RMI_F3A_MAX_REG_SIZE 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_START 3 218c2ecf20Sopenharmony_ci#define TRACKSTICK_RANGE_END 6 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct f3a_data { 248c2ecf20Sopenharmony_ci /* Query Data */ 258c2ecf20Sopenharmony_ci u8 gpio_count; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci u8 register_count; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci u8 data_regs[RMI_F3A_DATA_REGS_MAX_SIZE]; 308c2ecf20Sopenharmony_ci u16 *gpio_key_map; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci struct input_dev *input; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci struct rmi_function *f03; 358c2ecf20Sopenharmony_ci bool trackstick_buttons; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic void rmi_f3a_report_button(struct rmi_function *fn, 398c2ecf20Sopenharmony_ci struct f3a_data *f3a, unsigned int button) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci u16 key_code = f3a->gpio_key_map[button]; 428c2ecf20Sopenharmony_ci bool key_down = !(f3a->data_regs[0] & BIT(button)); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (f3a->trackstick_buttons && 458c2ecf20Sopenharmony_ci button >= TRACKSTICK_RANGE_START && 468c2ecf20Sopenharmony_ci button <= TRACKSTICK_RANGE_END) { 478c2ecf20Sopenharmony_ci rmi_f03_overwrite_button(f3a->f03, key_code, key_down); 488c2ecf20Sopenharmony_ci } else { 498c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, 508c2ecf20Sopenharmony_ci "%s: call input report key (0x%04x) value (0x%02x)", 518c2ecf20Sopenharmony_ci __func__, key_code, key_down); 528c2ecf20Sopenharmony_ci input_report_key(f3a->input, key_code, key_down); 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic irqreturn_t rmi_f3a_attention(int irq, void *ctx) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct rmi_function *fn = ctx; 598c2ecf20Sopenharmony_ci struct f3a_data *f3a = dev_get_drvdata(&fn->dev); 608c2ecf20Sopenharmony_ci struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); 618c2ecf20Sopenharmony_ci int error; 628c2ecf20Sopenharmony_ci int i; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (drvdata->attn_data.data) { 658c2ecf20Sopenharmony_ci if (drvdata->attn_data.size < f3a->register_count) { 668c2ecf20Sopenharmony_ci dev_warn(&fn->dev, 678c2ecf20Sopenharmony_ci "F3A interrupted, but data is missing\n"); 688c2ecf20Sopenharmony_ci return IRQ_HANDLED; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci memcpy(f3a->data_regs, drvdata->attn_data.data, 718c2ecf20Sopenharmony_ci f3a->register_count); 728c2ecf20Sopenharmony_ci drvdata->attn_data.data += f3a->register_count; 738c2ecf20Sopenharmony_ci drvdata->attn_data.size -= f3a->register_count; 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, 768c2ecf20Sopenharmony_ci f3a->data_regs, f3a->register_count); 778c2ecf20Sopenharmony_ci if (error) { 788c2ecf20Sopenharmony_ci dev_err(&fn->dev, 798c2ecf20Sopenharmony_ci "%s: Failed to read F3a data registers: %d\n", 808c2ecf20Sopenharmony_ci __func__, error); 818c2ecf20Sopenharmony_ci return IRQ_RETVAL(error); 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci for (i = 0; i < f3a->gpio_count; i++) 868c2ecf20Sopenharmony_ci if (f3a->gpio_key_map[i] != KEY_RESERVED) 878c2ecf20Sopenharmony_ci rmi_f3a_report_button(fn, f3a, i); 888c2ecf20Sopenharmony_ci if (f3a->trackstick_buttons) 898c2ecf20Sopenharmony_ci rmi_f03_commit_buttons(f3a->f03); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return IRQ_HANDLED; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic int rmi_f3a_config(struct rmi_function *fn) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci struct f3a_data *f3a = dev_get_drvdata(&fn->dev); 978c2ecf20Sopenharmony_ci struct rmi_driver *drv = fn->rmi_dev->driver; 988c2ecf20Sopenharmony_ci const struct rmi_device_platform_data *pdata = 998c2ecf20Sopenharmony_ci rmi_get_platform_data(fn->rmi_dev); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!f3a) 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (pdata->gpio_data.trackstick_buttons) { 1058c2ecf20Sopenharmony_ci /* Try [re-]establish link to F03. */ 1068c2ecf20Sopenharmony_ci f3a->f03 = rmi_find_function(fn->rmi_dev, 0x03); 1078c2ecf20Sopenharmony_ci f3a->trackstick_buttons = f3a->f03 != NULL; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic bool rmi_f3a_is_valid_button(int button, struct f3a_data *f3a, 1168c2ecf20Sopenharmony_ci u8 *query1_regs, u8 *ctrl1_regs) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci /* gpio exist && direction input */ 1198c2ecf20Sopenharmony_ci return (query1_regs[0] & BIT(button)) && !(ctrl1_regs[0] & BIT(button)); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a, 1238c2ecf20Sopenharmony_ci u8 *query1_regs, u8 *ctrl1_regs) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci const struct rmi_device_platform_data *pdata = 1268c2ecf20Sopenharmony_ci rmi_get_platform_data(fn->rmi_dev); 1278c2ecf20Sopenharmony_ci struct input_dev *input = f3a->input; 1288c2ecf20Sopenharmony_ci unsigned int button = BTN_LEFT; 1298c2ecf20Sopenharmony_ci unsigned int trackstick_button = BTN_LEFT; 1308c2ecf20Sopenharmony_ci bool button_mapped = false; 1318c2ecf20Sopenharmony_ci int i; 1328c2ecf20Sopenharmony_ci int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci f3a->gpio_key_map = devm_kcalloc(&fn->dev, 1358c2ecf20Sopenharmony_ci button_count, 1368c2ecf20Sopenharmony_ci sizeof(f3a->gpio_key_map[0]), 1378c2ecf20Sopenharmony_ci GFP_KERNEL); 1388c2ecf20Sopenharmony_ci if (!f3a->gpio_key_map) { 1398c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to allocate gpio map memory.\n"); 1408c2ecf20Sopenharmony_ci return -ENOMEM; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (i = 0; i < button_count; i++) { 1448c2ecf20Sopenharmony_ci if (!rmi_f3a_is_valid_button(i, f3a, query1_regs, ctrl1_regs)) 1458c2ecf20Sopenharmony_ci continue; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (pdata->gpio_data.trackstick_buttons && 1488c2ecf20Sopenharmony_ci i >= TRACKSTICK_RANGE_START && 1498c2ecf20Sopenharmony_ci i < TRACKSTICK_RANGE_END) { 1508c2ecf20Sopenharmony_ci f3a->gpio_key_map[i] = trackstick_button++; 1518c2ecf20Sopenharmony_ci } else if (!pdata->gpio_data.buttonpad || !button_mapped) { 1528c2ecf20Sopenharmony_ci f3a->gpio_key_map[i] = button; 1538c2ecf20Sopenharmony_ci input_set_capability(input, EV_KEY, button++); 1548c2ecf20Sopenharmony_ci button_mapped = true; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci input->keycode = f3a->gpio_key_map; 1588c2ecf20Sopenharmony_ci input->keycodesize = sizeof(f3a->gpio_key_map[0]); 1598c2ecf20Sopenharmony_ci input->keycodemax = f3a->gpio_count; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1)) 1628c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int rmi_f3a_initialize(struct rmi_function *fn, struct f3a_data *f3a) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci u8 query1[RMI_F3A_MAX_REG_SIZE]; 1708c2ecf20Sopenharmony_ci u8 ctrl1[RMI_F3A_MAX_REG_SIZE]; 1718c2ecf20Sopenharmony_ci u8 buf; 1728c2ecf20Sopenharmony_ci int error; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &buf); 1758c2ecf20Sopenharmony_ci if (error < 0) { 1768c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to read general info register: %d\n", 1778c2ecf20Sopenharmony_ci error); 1788c2ecf20Sopenharmony_ci return -ENODEV; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci f3a->gpio_count = buf & RMI_F3A_GPIO_COUNT; 1828c2ecf20Sopenharmony_ci f3a->register_count = DIV_ROUND_UP(f3a->gpio_count, 8); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Query1 -> gpio exist */ 1858c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1, 1868c2ecf20Sopenharmony_ci query1, f3a->register_count); 1878c2ecf20Sopenharmony_ci if (error) { 1888c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to read query1 register\n"); 1898c2ecf20Sopenharmony_ci return error; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Ctrl1 -> gpio direction */ 1938c2ecf20Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr + 1, 1948c2ecf20Sopenharmony_ci ctrl1, f3a->register_count); 1958c2ecf20Sopenharmony_ci if (error) { 1968c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Failed to read control1 register\n"); 1978c2ecf20Sopenharmony_ci return error; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci error = rmi_f3a_map_gpios(fn, f3a, query1, ctrl1); 2018c2ecf20Sopenharmony_ci if (error) 2028c2ecf20Sopenharmony_ci return error; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int rmi_f3a_probe(struct rmi_function *fn) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 2108c2ecf20Sopenharmony_ci struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 2118c2ecf20Sopenharmony_ci struct f3a_data *f3a; 2128c2ecf20Sopenharmony_ci int error; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (!drv_data->input) { 2158c2ecf20Sopenharmony_ci dev_info(&fn->dev, "F3A: no input device found, ignoring\n"); 2168c2ecf20Sopenharmony_ci return -ENXIO; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci f3a = devm_kzalloc(&fn->dev, sizeof(*f3a), GFP_KERNEL); 2208c2ecf20Sopenharmony_ci if (!f3a) 2218c2ecf20Sopenharmony_ci return -ENOMEM; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci f3a->input = drv_data->input; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci error = rmi_f3a_initialize(fn, f3a); 2268c2ecf20Sopenharmony_ci if (error) 2278c2ecf20Sopenharmony_ci return error; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci dev_set_drvdata(&fn->dev, f3a); 2308c2ecf20Sopenharmony_ci return 0; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistruct rmi_function_handler rmi_f3a_handler = { 2348c2ecf20Sopenharmony_ci .driver = { 2358c2ecf20Sopenharmony_ci .name = "rmi4_f3a", 2368c2ecf20Sopenharmony_ci }, 2378c2ecf20Sopenharmony_ci .func = 0x3a, 2388c2ecf20Sopenharmony_ci .probe = rmi_f3a_probe, 2398c2ecf20Sopenharmony_ci .config = rmi_f3a_config, 2408c2ecf20Sopenharmony_ci .attention = rmi_f3a_attention, 2418c2ecf20Sopenharmony_ci}; 242