162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2012-2015 Synaptics Incorporated 462306a36Sopenharmony_ci * Copyright (C) 2016 Zodiac Inflight Innovations 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/bitops.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/rmi.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include "rmi_driver.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define F55_NAME "rmi4_f55" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* F55 data offsets */ 1662306a36Sopenharmony_ci#define F55_NUM_RX_OFFSET 0 1762306a36Sopenharmony_ci#define F55_NUM_TX_OFFSET 1 1862306a36Sopenharmony_ci#define F55_PHYS_CHAR_OFFSET 2 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Only read required query registers */ 2162306a36Sopenharmony_ci#define F55_QUERY_LEN 3 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* F55 capabilities */ 2462306a36Sopenharmony_ci#define F55_CAP_SENSOR_ASSIGN BIT(0) 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct f55_data { 2762306a36Sopenharmony_ci struct rmi_function *fn; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci u8 qry[F55_QUERY_LEN]; 3062306a36Sopenharmony_ci u8 num_rx_electrodes; 3162306a36Sopenharmony_ci u8 cfg_num_rx_electrodes; 3262306a36Sopenharmony_ci u8 num_tx_electrodes; 3362306a36Sopenharmony_ci u8 cfg_num_tx_electrodes; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic int rmi_f55_detect(struct rmi_function *fn) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 3962306a36Sopenharmony_ci struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 4062306a36Sopenharmony_ci struct f55_data *f55; 4162306a36Sopenharmony_ci int error; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci f55 = dev_get_drvdata(&fn->dev); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, 4662306a36Sopenharmony_ci &f55->qry, sizeof(f55->qry)); 4762306a36Sopenharmony_ci if (error) { 4862306a36Sopenharmony_ci dev_err(&fn->dev, "%s: Failed to query F55 properties\n", 4962306a36Sopenharmony_ci __func__); 5062306a36Sopenharmony_ci return error; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET]; 5462306a36Sopenharmony_ci f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET]; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci f55->cfg_num_rx_electrodes = f55->num_rx_electrodes; 5762306a36Sopenharmony_ci f55->cfg_num_tx_electrodes = f55->num_rx_electrodes; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes; 6062306a36Sopenharmony_ci drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) { 6362306a36Sopenharmony_ci int i, total; 6462306a36Sopenharmony_ci u8 buf[256]; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * Calculate the number of enabled receive and transmit 6862306a36Sopenharmony_ci * electrodes by reading F55:Ctrl1 (sensor receiver assignment) 6962306a36Sopenharmony_ci * and F55:Ctrl2 (sensor transmitter assignment). The number of 7062306a36Sopenharmony_ci * enabled electrodes is the sum of all field entries with a 7162306a36Sopenharmony_ci * value other than 0xff. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, 7462306a36Sopenharmony_ci fn->fd.control_base_addr + 1, 7562306a36Sopenharmony_ci buf, f55->num_rx_electrodes); 7662306a36Sopenharmony_ci if (!error) { 7762306a36Sopenharmony_ci total = 0; 7862306a36Sopenharmony_ci for (i = 0; i < f55->num_rx_electrodes; i++) { 7962306a36Sopenharmony_ci if (buf[i] != 0xff) 8062306a36Sopenharmony_ci total++; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci f55->cfg_num_rx_electrodes = total; 8362306a36Sopenharmony_ci drv_data->num_rx_electrodes = total; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci error = rmi_read_block(fn->rmi_dev, 8762306a36Sopenharmony_ci fn->fd.control_base_addr + 2, 8862306a36Sopenharmony_ci buf, f55->num_tx_electrodes); 8962306a36Sopenharmony_ci if (!error) { 9062306a36Sopenharmony_ci total = 0; 9162306a36Sopenharmony_ci for (i = 0; i < f55->num_tx_electrodes; i++) { 9262306a36Sopenharmony_ci if (buf[i] != 0xff) 9362306a36Sopenharmony_ci total++; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci f55->cfg_num_tx_electrodes = total; 9662306a36Sopenharmony_ci drv_data->num_tx_electrodes = total; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n", 10162306a36Sopenharmony_ci f55->cfg_num_rx_electrodes, f55->num_rx_electrodes); 10262306a36Sopenharmony_ci rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n", 10362306a36Sopenharmony_ci f55->cfg_num_tx_electrodes, f55->num_tx_electrodes); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int rmi_f55_probe(struct rmi_function *fn) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct f55_data *f55; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL); 11362306a36Sopenharmony_ci if (!f55) 11462306a36Sopenharmony_ci return -ENOMEM; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci f55->fn = fn; 11762306a36Sopenharmony_ci dev_set_drvdata(&fn->dev, f55); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return rmi_f55_detect(fn); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistruct rmi_function_handler rmi_f55_handler = { 12362306a36Sopenharmony_ci .driver = { 12462306a36Sopenharmony_ci .name = F55_NAME, 12562306a36Sopenharmony_ci }, 12662306a36Sopenharmony_ci .func = 0x55, 12762306a36Sopenharmony_ci .probe = rmi_f55_probe, 12862306a36Sopenharmony_ci}; 129