1/*
2 * Copyright (c) 2012-2015 Synaptics Incorporated
3 * Copyright (C) 2016 Zodiac Inflight Innovations
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 */
9
10#include <linux/bitops.h>
11#include <linux/kernel.h>
12#include <linux/rmi.h>
13#include <linux/slab.h>
14#include "rmi_driver.h"
15
16#define F55_NAME "rmi4_f55"
17
18/* F55 data offsets */
19#define F55_NUM_RX_OFFSET 0
20#define F55_NUM_TX_OFFSET 1
21#define F55_PHYS_CHAR_OFFSET 2
22
23/* Only read required query registers */
24#define F55_QUERY_LEN 3
25
26/* F55 capabilities */
27#define F55_CAP_SENSOR_ASSIGN BIT(0)
28
29struct f55_data {
30 struct rmi_function *fn;
31
32 u8 qry[F55_QUERY_LEN];
33 u8 num_rx_electrodes;
34 u8 cfg_num_rx_electrodes;
35 u8 num_tx_electrodes;
36 u8 cfg_num_tx_electrodes;
37};
38
39static int rmi_f55_detect(struct rmi_function *fn)
40{
41 struct rmi_device *rmi_dev = fn->rmi_dev;
42 struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
43 struct f55_data *f55;
44 int error;
45
46 f55 = dev_get_drvdata(&fn->dev);
47
48 error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
49 &f55->qry, sizeof(f55->qry));
50 if (error) {
51 dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
52 __func__);
53 return error;
54 }
55
56 f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
57 f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
58
59 f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
60 f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
61
62 drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
63 drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
64
65 if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
66 int i, total;
67 u8 buf[256];
68
69 /*
70 * Calculate the number of enabled receive and transmit
71 * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
72 * and F55:Ctrl2 (sensor transmitter assignment). The number of
73 * enabled electrodes is the sum of all field entries with a
74 * value other than 0xff.
75 */
76 error = rmi_read_block(fn->rmi_dev,
77 fn->fd.control_base_addr + 1,
78 buf, f55->num_rx_electrodes);
79 if (!error) {
80 total = 0;
81 for (i = 0; i < f55->num_rx_electrodes; i++) {
82 if (buf[i] != 0xff)
83 total++;
84 }
85 f55->cfg_num_rx_electrodes = total;
86 drv_data->num_rx_electrodes = total;
87 }
88
89 error = rmi_read_block(fn->rmi_dev,
90 fn->fd.control_base_addr + 2,
91 buf, f55->num_tx_electrodes);
92 if (!error) {
93 total = 0;
94 for (i = 0; i < f55->num_tx_electrodes; i++) {
95 if (buf[i] != 0xff)
96 total++;
97 }
98 f55->cfg_num_tx_electrodes = total;
99 drv_data->num_tx_electrodes = total;
100 }
101 }
102
103 rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
104 f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
105 rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
106 f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
107
108 return 0;
109}
110
111static int rmi_f55_probe(struct rmi_function *fn)
112{
113 struct f55_data *f55;
114
115 f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
116 if (!f55)
117 return -ENOMEM;
118
119 f55->fn = fn;
120 dev_set_drvdata(&fn->dev, f55);
121
122 return rmi_f55_detect(fn);
123}
124
125struct rmi_function_handler rmi_f55_handler = {
126 .driver = {
127 .name = F55_NAME,
128 },
129 .func = 0x55,
130 .probe = rmi_f55_probe,
131};
132