18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2012-2015 Synaptics Incorporated
48c2ecf20Sopenharmony_ci * Copyright (C) 2016 Zodiac Inflight Innovations
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/rmi.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include "rmi_driver.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define F55_NAME		"rmi4_f55"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* F55 data offsets */
168c2ecf20Sopenharmony_ci#define F55_NUM_RX_OFFSET	0
178c2ecf20Sopenharmony_ci#define F55_NUM_TX_OFFSET	1
188c2ecf20Sopenharmony_ci#define F55_PHYS_CHAR_OFFSET	2
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* Only read required query registers */
218c2ecf20Sopenharmony_ci#define F55_QUERY_LEN		3
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* F55 capabilities */
248c2ecf20Sopenharmony_ci#define F55_CAP_SENSOR_ASSIGN	BIT(0)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct f55_data {
278c2ecf20Sopenharmony_ci	struct rmi_function *fn;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	u8 qry[F55_QUERY_LEN];
308c2ecf20Sopenharmony_ci	u8 num_rx_electrodes;
318c2ecf20Sopenharmony_ci	u8 cfg_num_rx_electrodes;
328c2ecf20Sopenharmony_ci	u8 num_tx_electrodes;
338c2ecf20Sopenharmony_ci	u8 cfg_num_tx_electrodes;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int rmi_f55_detect(struct rmi_function *fn)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct rmi_device *rmi_dev = fn->rmi_dev;
398c2ecf20Sopenharmony_ci	struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
408c2ecf20Sopenharmony_ci	struct f55_data *f55;
418c2ecf20Sopenharmony_ci	int error;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	f55 = dev_get_drvdata(&fn->dev);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
468c2ecf20Sopenharmony_ci			       &f55->qry, sizeof(f55->qry));
478c2ecf20Sopenharmony_ci	if (error) {
488c2ecf20Sopenharmony_ci		dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
498c2ecf20Sopenharmony_ci			__func__);
508c2ecf20Sopenharmony_ci		return error;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
548c2ecf20Sopenharmony_ci	f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
578c2ecf20Sopenharmony_ci	f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
608c2ecf20Sopenharmony_ci	drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
638c2ecf20Sopenharmony_ci		int i, total;
648c2ecf20Sopenharmony_ci		u8 buf[256];
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		/*
678c2ecf20Sopenharmony_ci		 * Calculate the number of enabled receive and transmit
688c2ecf20Sopenharmony_ci		 * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
698c2ecf20Sopenharmony_ci		 * and F55:Ctrl2 (sensor transmitter assignment). The number of
708c2ecf20Sopenharmony_ci		 * enabled electrodes is the sum of all field entries with a
718c2ecf20Sopenharmony_ci		 * value other than 0xff.
728c2ecf20Sopenharmony_ci		 */
738c2ecf20Sopenharmony_ci		error = rmi_read_block(fn->rmi_dev,
748c2ecf20Sopenharmony_ci				       fn->fd.control_base_addr + 1,
758c2ecf20Sopenharmony_ci				       buf, f55->num_rx_electrodes);
768c2ecf20Sopenharmony_ci		if (!error) {
778c2ecf20Sopenharmony_ci			total = 0;
788c2ecf20Sopenharmony_ci			for (i = 0; i < f55->num_rx_electrodes; i++) {
798c2ecf20Sopenharmony_ci				if (buf[i] != 0xff)
808c2ecf20Sopenharmony_ci					total++;
818c2ecf20Sopenharmony_ci			}
828c2ecf20Sopenharmony_ci			f55->cfg_num_rx_electrodes = total;
838c2ecf20Sopenharmony_ci			drv_data->num_rx_electrodes = total;
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		error = rmi_read_block(fn->rmi_dev,
878c2ecf20Sopenharmony_ci				       fn->fd.control_base_addr + 2,
888c2ecf20Sopenharmony_ci				       buf, f55->num_tx_electrodes);
898c2ecf20Sopenharmony_ci		if (!error) {
908c2ecf20Sopenharmony_ci			total = 0;
918c2ecf20Sopenharmony_ci			for (i = 0; i < f55->num_tx_electrodes; i++) {
928c2ecf20Sopenharmony_ci				if (buf[i] != 0xff)
938c2ecf20Sopenharmony_ci					total++;
948c2ecf20Sopenharmony_ci			}
958c2ecf20Sopenharmony_ci			f55->cfg_num_tx_electrodes = total;
968c2ecf20Sopenharmony_ci			drv_data->num_tx_electrodes = total;
978c2ecf20Sopenharmony_ci		}
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
1018c2ecf20Sopenharmony_ci		f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
1028c2ecf20Sopenharmony_ci	rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
1038c2ecf20Sopenharmony_ci		f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int rmi_f55_probe(struct rmi_function *fn)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct f55_data *f55;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
1138c2ecf20Sopenharmony_ci	if (!f55)
1148c2ecf20Sopenharmony_ci		return -ENOMEM;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	f55->fn = fn;
1178c2ecf20Sopenharmony_ci	dev_set_drvdata(&fn->dev, f55);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return rmi_f55_detect(fn);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistruct rmi_function_handler rmi_f55_handler = {
1238c2ecf20Sopenharmony_ci	.driver = {
1248c2ecf20Sopenharmony_ci		.name = F55_NAME,
1258c2ecf20Sopenharmony_ci	},
1268c2ecf20Sopenharmony_ci	.func = 0x55,
1278c2ecf20Sopenharmony_ci	.probe = rmi_f55_probe,
1288c2ecf20Sopenharmony_ci};
129