1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26adba43fSGuenter Roeck /*
36adba43fSGuenter Roeck * Copyright (c) 2012-2015 Synaptics Incorporated
46adba43fSGuenter Roeck * Copyright (C) 2016 Zodiac Inflight Innovations
56adba43fSGuenter Roeck */
66adba43fSGuenter Roeck
76adba43fSGuenter Roeck #include <linux/bitops.h>
86adba43fSGuenter Roeck #include <linux/kernel.h>
96adba43fSGuenter Roeck #include <linux/rmi.h>
106adba43fSGuenter Roeck #include <linux/slab.h>
116adba43fSGuenter Roeck #include "rmi_driver.h"
126adba43fSGuenter Roeck
136adba43fSGuenter Roeck #define F55_NAME "rmi4_f55"
146adba43fSGuenter Roeck
156adba43fSGuenter Roeck /* F55 data offsets */
166adba43fSGuenter Roeck #define F55_NUM_RX_OFFSET 0
176adba43fSGuenter Roeck #define F55_NUM_TX_OFFSET 1
186adba43fSGuenter Roeck #define F55_PHYS_CHAR_OFFSET 2
196adba43fSGuenter Roeck
206adba43fSGuenter Roeck /* Only read required query registers */
216adba43fSGuenter Roeck #define F55_QUERY_LEN 3
226adba43fSGuenter Roeck
236adba43fSGuenter Roeck /* F55 capabilities */
246adba43fSGuenter Roeck #define F55_CAP_SENSOR_ASSIGN BIT(0)
256adba43fSGuenter Roeck
266adba43fSGuenter Roeck struct f55_data {
276adba43fSGuenter Roeck struct rmi_function *fn;
286adba43fSGuenter Roeck
296adba43fSGuenter Roeck u8 qry[F55_QUERY_LEN];
306adba43fSGuenter Roeck u8 num_rx_electrodes;
316adba43fSGuenter Roeck u8 cfg_num_rx_electrodes;
326adba43fSGuenter Roeck u8 num_tx_electrodes;
336adba43fSGuenter Roeck u8 cfg_num_tx_electrodes;
346adba43fSGuenter Roeck };
356adba43fSGuenter Roeck
rmi_f55_detect(struct rmi_function * fn)366adba43fSGuenter Roeck static int rmi_f55_detect(struct rmi_function *fn)
376adba43fSGuenter Roeck {
38c762cc68SGuenter Roeck struct rmi_device *rmi_dev = fn->rmi_dev;
39c762cc68SGuenter Roeck struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
406adba43fSGuenter Roeck struct f55_data *f55;
416adba43fSGuenter Roeck int error;
426adba43fSGuenter Roeck
436adba43fSGuenter Roeck f55 = dev_get_drvdata(&fn->dev);
446adba43fSGuenter Roeck
456adba43fSGuenter Roeck error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
466adba43fSGuenter Roeck &f55->qry, sizeof(f55->qry));
476adba43fSGuenter Roeck if (error) {
486adba43fSGuenter Roeck dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
496adba43fSGuenter Roeck __func__);
506adba43fSGuenter Roeck return error;
516adba43fSGuenter Roeck }
526adba43fSGuenter Roeck
536adba43fSGuenter Roeck f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
546adba43fSGuenter Roeck f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
556adba43fSGuenter Roeck
566adba43fSGuenter Roeck f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
576adba43fSGuenter Roeck f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
586adba43fSGuenter Roeck
59c762cc68SGuenter Roeck drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
60c762cc68SGuenter Roeck drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
61c762cc68SGuenter Roeck
626adba43fSGuenter Roeck if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
636adba43fSGuenter Roeck int i, total;
646adba43fSGuenter Roeck u8 buf[256];
656adba43fSGuenter Roeck
666adba43fSGuenter Roeck /*
676adba43fSGuenter Roeck * Calculate the number of enabled receive and transmit
686adba43fSGuenter Roeck * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
696adba43fSGuenter Roeck * and F55:Ctrl2 (sensor transmitter assignment). The number of
706adba43fSGuenter Roeck * enabled electrodes is the sum of all field entries with a
716adba43fSGuenter Roeck * value other than 0xff.
726adba43fSGuenter Roeck */
736adba43fSGuenter Roeck error = rmi_read_block(fn->rmi_dev,
746adba43fSGuenter Roeck fn->fd.control_base_addr + 1,
756adba43fSGuenter Roeck buf, f55->num_rx_electrodes);
766adba43fSGuenter Roeck if (!error) {
776adba43fSGuenter Roeck total = 0;
786adba43fSGuenter Roeck for (i = 0; i < f55->num_rx_electrodes; i++) {
796adba43fSGuenter Roeck if (buf[i] != 0xff)
806adba43fSGuenter Roeck total++;
816adba43fSGuenter Roeck }
826adba43fSGuenter Roeck f55->cfg_num_rx_electrodes = total;
83c762cc68SGuenter Roeck drv_data->num_rx_electrodes = total;
846adba43fSGuenter Roeck }
856adba43fSGuenter Roeck
866adba43fSGuenter Roeck error = rmi_read_block(fn->rmi_dev,
876adba43fSGuenter Roeck fn->fd.control_base_addr + 2,
886adba43fSGuenter Roeck buf, f55->num_tx_electrodes);
896adba43fSGuenter Roeck if (!error) {
906adba43fSGuenter Roeck total = 0;
916adba43fSGuenter Roeck for (i = 0; i < f55->num_tx_electrodes; i++) {
926adba43fSGuenter Roeck if (buf[i] != 0xff)
936adba43fSGuenter Roeck total++;
946adba43fSGuenter Roeck }
956adba43fSGuenter Roeck f55->cfg_num_tx_electrodes = total;
96c762cc68SGuenter Roeck drv_data->num_tx_electrodes = total;
976adba43fSGuenter Roeck }
986adba43fSGuenter Roeck }
996adba43fSGuenter Roeck
1006adba43fSGuenter Roeck rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
1016adba43fSGuenter Roeck f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
1026adba43fSGuenter Roeck rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
1036adba43fSGuenter Roeck f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
1046adba43fSGuenter Roeck
1056adba43fSGuenter Roeck return 0;
1066adba43fSGuenter Roeck }
1076adba43fSGuenter Roeck
rmi_f55_probe(struct rmi_function * fn)1086adba43fSGuenter Roeck static int rmi_f55_probe(struct rmi_function *fn)
1096adba43fSGuenter Roeck {
1106adba43fSGuenter Roeck struct f55_data *f55;
1116adba43fSGuenter Roeck
1126adba43fSGuenter Roeck f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
1136adba43fSGuenter Roeck if (!f55)
1146adba43fSGuenter Roeck return -ENOMEM;
1156adba43fSGuenter Roeck
1166adba43fSGuenter Roeck f55->fn = fn;
1176adba43fSGuenter Roeck dev_set_drvdata(&fn->dev, f55);
1186adba43fSGuenter Roeck
1196adba43fSGuenter Roeck return rmi_f55_detect(fn);
1206adba43fSGuenter Roeck }
1216adba43fSGuenter Roeck
1226adba43fSGuenter Roeck struct rmi_function_handler rmi_f55_handler = {
1236adba43fSGuenter Roeck .driver = {
1246adba43fSGuenter Roeck .name = F55_NAME,
1256adba43fSGuenter Roeck },
1266adba43fSGuenter Roeck .func = 0x55,
1276adba43fSGuenter Roeck .probe = rmi_f55_probe,
1286adba43fSGuenter Roeck };
129