aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBryan Wu <cooloney@kernel.org>2010-03-22 02:23:24 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-04-14 02:27:16 -0400
commit31a6296333b94964e9a073649840bb34d4603369 (patch)
tree18c209d358420a889bc93e376d92e176cffb2326 /drivers
parenta5b33e6a207d75120ad9dad0b5401b561991dcce (diff)
Input: add Analog Devices AD714x captouch input driver
AD7142 and AD7147 are integrated capacitance-to-digital converters (CDCs) with on-chip environmental calibration for use in systems requiring a novel user input method. The AD7142 and AD7147 can interface to external capacitance sensors implementing functions such as buttons, scrollwheels, sliders, touchpads and so on. The chips don't restrict the specific usage. Depending on the hardware connection, one special target board can include one or several these components. The platform_data for the device's "struct device" holds these information. The data-struct defined in head file descript the hardware feature of button/scrollwheel/slider/touchpad components on target boards, which need be filled in the arch/mach-/. As the result, the driver is independent of boards. It gets the components layout from the platform_data, registers related devices, fullfills the algorithms and state machines for these components and report related input events to up level. Signed-off-by: Bryan Wu <cooloney@kernel.org> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com> Signed-off-by: Barry Song <21cnbao@gmail.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/misc/Kconfig30
-rw-r--r--drivers/input/misc/Makefile3
-rw-r--r--drivers/input/misc/ad714x-i2c.c137
-rw-r--r--drivers/input/misc/ad714x-spi.c103
-rw-r--r--drivers/input/misc/ad714x.c1331
-rw-r--r--drivers/input/misc/ad714x.h26
6 files changed, 1630 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 54a9c2d0ba1c..a4b9dc5cf456 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -22,6 +22,36 @@ config INPUT_88PM860X_ONKEY
22 To compile this driver as a module, choose M here: the module 22 To compile this driver as a module, choose M here: the module
23 will be called 88pm860x_onkey. 23 will be called 88pm860x_onkey.
24 24
25config INPUT_AD714X
26 tristate "Analog Devices AD714x Capacitance Touch Sensor"
27 help
28 Say Y here if you want to support an AD7142/AD7147 touch sensor.
29
30 You should select a bus connection too.
31
32 To compile this driver as a module, choose M here: the
33 module will be called ad714x.
34
35config INPUT_AD714X_I2C
36 tristate "support I2C bus connection"
37 depends on INPUT_AD714X && I2C
38 default y
39 help
40 Say Y here if you have AD7142/AD7147 hooked to an I2C bus.
41
42 To compile this driver as a module, choose M here: the
43 module will be called ad714x-i2c.
44
45config INPUT_AD714X_SPI
46 tristate "support SPI bus connection"
47 depends on INPUT_AD714X && SPI
48 default y
49 help
50 Say Y here if you have AD7142/AD7147 hooked to a SPI bus.
51
52 To compile this driver as a module, choose M here: the
53 module will be called ad714x-spi.
54
25config INPUT_PCSPKR 55config INPUT_PCSPKR
26 tristate "PC Speaker support" 56 tristate "PC Speaker support"
27 depends on PCSPKR_PLATFORM 57 depends on PCSPKR_PLATFORM
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index a662df21bf57..f9f577031e06 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -5,6 +5,9 @@
5# Each configuration option enables a list of files. 5# Each configuration option enables a list of files.
6 6
7obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o 7obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
8obj-$(CONFIG_INPUT_AD714X) += ad714x.o
9obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
10obj-$(CONFIG_INPUT_AD714X_SPI) += ad714x-spi.o
8obj-$(CONFIG_INPUT_APANEL) += apanel.o 11obj-$(CONFIG_INPUT_APANEL) += apanel.o
9obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o 12obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
10obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o 13obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
new file mode 100644
index 000000000000..a2cb6b426dc7
--- /dev/null
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -0,0 +1,137 @@
1/*
2 * AD714X CapTouch Programmable Controller driver (I2C bus)
3 *
4 * Copyright 2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/input.h> /* BUS_I2C */
10#include <linux/i2c.h>
11#include <linux/module.h>
12#include <linux/types.h>
13#include "ad714x.h"
14
15#ifdef CONFIG_PM
16static int ad714x_i2c_suspend(struct i2c_client *client, pm_message_t message)
17{
18 return ad714x_disable(i2c_get_clientdata(client));
19}
20
21static int ad714x_i2c_resume(struct i2c_client *client)
22{
23 return ad714x_enable(i2c_get_clientdata(client));
24}
25#else
26# define ad714x_i2c_suspend NULL
27# define ad714x_i2c_resume NULL
28#endif
29
30static int ad714x_i2c_write(struct device *dev, unsigned short reg,
31 unsigned short data)
32{
33 struct i2c_client *client = to_i2c_client(dev);
34 int ret = 0;
35 u8 *_reg = (u8 *)&reg;
36 u8 *_data = (u8 *)&data;
37
38 u8 tx[4] = {
39 _reg[1],
40 _reg[0],
41 _data[1],
42 _data[0]
43 };
44
45 ret = i2c_master_send(client, tx, 4);
46 if (ret < 0)
47 dev_err(&client->dev, "I2C write error\n");
48
49 return ret;
50}
51
52static int ad714x_i2c_read(struct device *dev, unsigned short reg,
53 unsigned short *data)
54{
55 struct i2c_client *client = to_i2c_client(dev);
56 int ret = 0;
57 u8 *_reg = (u8 *)&reg;
58 u8 *_data = (u8 *)data;
59
60 u8 tx[2] = {
61 _reg[1],
62 _reg[0]
63 };
64 u8 rx[2];
65
66 ret = i2c_master_send(client, tx, 2);
67 if (ret >= 0)
68 ret = i2c_master_recv(client, rx, 2);
69
70 if (unlikely(ret < 0)) {
71 dev_err(&client->dev, "I2C read error\n");
72 } else {
73 _data[0] = rx[1];
74 _data[1] = rx[0];
75 }
76
77 return ret;
78}
79
80static int __devinit ad714x_i2c_probe(struct i2c_client *client,
81 const struct i2c_device_id *id)
82{
83 struct ad714x_chip *chip;
84
85 chip = ad714x_probe(&client->dev, BUS_I2C, client->irq,
86 ad714x_i2c_read, ad714x_i2c_write);
87 if (IS_ERR(chip))
88 return PTR_ERR(chip);
89
90 i2c_set_clientdata(client, chip);
91
92 return 0;
93}
94
95static int __devexit ad714x_i2c_remove(struct i2c_client *client)
96{
97 struct ad714x_chip *chip = i2c_get_clientdata(client);
98
99 ad714x_remove(chip);
100 i2c_set_clientdata(client, NULL);
101
102 return 0;
103}
104
105static const struct i2c_device_id ad714x_id[] = {
106 { "ad7142_captouch", 0 },
107 { "ad7147_captouch", 0 },
108 { }
109};
110MODULE_DEVICE_TABLE(i2c, ad714x_id);
111
112static struct i2c_driver ad714x_i2c_driver = {
113 .driver = {
114 .name = "ad714x_captouch",
115 },
116 .probe = ad714x_i2c_probe,
117 .remove = __devexit_p(ad714x_i2c_remove),
118 .suspend = ad714x_i2c_suspend,
119 .resume = ad714x_i2c_resume,
120 .id_table = ad714x_id,
121};
122
123static __init int ad714x_i2c_init(void)
124{
125 return i2c_add_driver(&ad714x_i2c_driver);
126}
127module_init(ad714x_i2c_init);
128
129static __exit void ad714x_i2c_exit(void)
130{
131 i2c_del_driver(&ad714x_i2c_driver);
132}
133module_exit(ad714x_i2c_exit);
134
135MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver");
136MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
137MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
new file mode 100644
index 000000000000..7f8dedfd1bfe
--- /dev/null
+++ b/drivers/input/misc/ad714x-spi.c
@@ -0,0 +1,103 @@
1/*
2 * AD714X CapTouch Programmable Controller driver (SPI bus)
3 *
4 * Copyright 2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/input.h> /* BUS_I2C */
10#include <linux/module.h>
11#include <linux/spi/spi.h>
12#include <linux/types.h>
13#include "ad714x.h"
14
15#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */
16#define AD714x_SPI_READ BIT(10)
17
18#ifdef CONFIG_PM
19static int ad714x_spi_suspend(struct spi_device *spi, pm_message_t message)
20{
21 return ad714x_disable(spi_get_drvdata(spi));
22}
23
24static int ad714x_spi_resume(struct spi_device *spi)
25{
26 return ad714x_enable(spi_get_drvdata(spi));
27}
28#else
29# define ad714x_spi_suspend NULL
30# define ad714x_spi_resume NULL
31#endif
32
33static int ad714x_spi_read(struct device *dev, unsigned short reg,
34 unsigned short *data)
35{
36 struct spi_device *spi = to_spi_device(dev);
37 unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg;
38
39 return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2);
40}
41
42static int ad714x_spi_write(struct device *dev, unsigned short reg,
43 unsigned short data)
44{
45 struct spi_device *spi = to_spi_device(dev);
46 unsigned short tx[2] = {
47 AD714x_SPI_CMD_PREFIX | reg,
48 data
49 };
50
51 return spi_write(spi, (u8 *)tx, 4);
52}
53
54static int __devinit ad714x_spi_probe(struct spi_device *spi)
55{
56 struct ad714x_chip *chip;
57
58 chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
59 ad714x_spi_read, ad714x_spi_write);
60 if (IS_ERR(chip))
61 return PTR_ERR(chip);
62
63 spi_set_drvdata(spi, chip);
64
65 return 0;
66}
67
68static int __devexit ad714x_spi_remove(struct spi_device *spi)
69{
70 struct ad714x_chip *chip = spi_get_drvdata(spi);
71
72 ad714x_remove(chip);
73 spi_set_drvdata(spi, NULL);
74
75 return 0;
76}
77
78static struct spi_driver ad714x_spi_driver = {
79 .driver = {
80 .name = "ad714x_captouch",
81 .owner = THIS_MODULE,
82 },
83 .probe = ad714x_spi_probe,
84 .remove = __devexit_p(ad714x_spi_remove),
85 .suspend = ad714x_spi_suspend,
86 .resume = ad714x_spi_resume,
87};
88
89static __init int ad714x_spi_init(void)
90{
91 return spi_register_driver(&ad714x_spi_driver);
92}
93module_init(ad714x_spi_init);
94
95static __exit void ad714x_spi_exit(void)
96{
97 spi_unregister_driver(&ad714x_spi_driver);
98}
99module_exit(ad714x_spi_exit);
100
101MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
102MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
103MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
new file mode 100644
index 000000000000..691b1d37331f
--- /dev/null
+++ b/drivers/input/misc/ad714x.c
@@ -0,0 +1,1331 @@
1/*
2 * AD714X CapTouch Programmable Controller driver
3 *
4 * Copyright 2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/device.h>
10#include <linux/init.h>
11#include <linux/input.h>
12#include <linux/interrupt.h>
13#include <linux/slab.h>
14#include <linux/input/ad714x.h>
15#include "ad714x.h"
16
17#define AD714X_PWR_CTRL 0x0
18#define AD714X_STG_CAL_EN_REG 0x1
19#define AD714X_AMB_COMP_CTRL0_REG 0x2
20#define AD714X_PARTID_REG 0x17
21#define AD7147_PARTID 0x1470
22#define AD7142_PARTID 0xE620
23#define AD714X_STAGECFG_REG 0x80
24#define AD714X_SYSCFG_REG 0x0
25
26#define STG_LOW_INT_EN_REG 0x5
27#define STG_HIGH_INT_EN_REG 0x6
28#define STG_COM_INT_EN_REG 0x7
29#define STG_LOW_INT_STA_REG 0x8
30#define STG_HIGH_INT_STA_REG 0x9
31#define STG_COM_INT_STA_REG 0xA
32
33#define CDC_RESULT_S0 0xB
34#define CDC_RESULT_S1 0xC
35#define CDC_RESULT_S2 0xD
36#define CDC_RESULT_S3 0xE
37#define CDC_RESULT_S4 0xF
38#define CDC_RESULT_S5 0x10
39#define CDC_RESULT_S6 0x11
40#define CDC_RESULT_S7 0x12
41#define CDC_RESULT_S8 0x13
42#define CDC_RESULT_S9 0x14
43#define CDC_RESULT_S10 0x15
44#define CDC_RESULT_S11 0x16
45
46#define STAGE0_AMBIENT 0xF1
47#define STAGE1_AMBIENT 0x115
48#define STAGE2_AMBIENT 0x139
49#define STAGE3_AMBIENT 0x15D
50#define STAGE4_AMBIENT 0x181
51#define STAGE5_AMBIENT 0x1A5
52#define STAGE6_AMBIENT 0x1C9
53#define STAGE7_AMBIENT 0x1ED
54#define STAGE8_AMBIENT 0x211
55#define STAGE9_AMBIENT 0x234
56#define STAGE10_AMBIENT 0x259
57#define STAGE11_AMBIENT 0x27D
58
59#define PER_STAGE_REG_NUM 36
60#define STAGE_NUM 12
61#define STAGE_CFGREG_NUM 8
62#define SYS_CFGREG_NUM 8
63
64/*
65 * driver information which will be used to maintain the software flow
66 */
67enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
68
69struct ad714x_slider_drv {
70 int highest_stage;
71 int abs_pos;
72 int flt_pos;
73 enum ad714x_device_state state;
74 struct input_dev *input;
75};
76
77struct ad714x_wheel_drv {
78 int abs_pos;
79 int flt_pos;
80 int pre_mean_value;
81 int pre_highest_stage;
82 int pre_mean_value_no_offset;
83 int mean_value;
84 int mean_value_no_offset;
85 int pos_offset;
86 int pos_ratio;
87 int highest_stage;
88 enum ad714x_device_state state;
89 struct input_dev *input;
90};
91
92struct ad714x_touchpad_drv {
93 int x_highest_stage;
94 int x_flt_pos;
95 int x_abs_pos;
96 int y_highest_stage;
97 int y_flt_pos;
98 int y_abs_pos;
99 int left_ep;
100 int left_ep_val;
101 int right_ep;
102 int right_ep_val;
103 int top_ep;
104 int top_ep_val;
105 int bottom_ep;
106 int bottom_ep_val;
107 enum ad714x_device_state state;
108 struct input_dev *input;
109};
110
111struct ad714x_button_drv {
112 enum ad714x_device_state state;
113 /*
114 * Unlike slider/wheel/touchpad, all buttons point to
115 * same input_dev instance
116 */
117 struct input_dev *input;
118};
119
120struct ad714x_driver_data {
121 struct ad714x_slider_drv *slider;
122 struct ad714x_wheel_drv *wheel;
123 struct ad714x_touchpad_drv *touchpad;
124 struct ad714x_button_drv *button;
125};
126
127/*
128 * information to integrate all things which will be private data
129 * of spi/i2c device
130 */
131struct ad714x_chip {
132 unsigned short h_state;
133 unsigned short l_state;
134 unsigned short c_state;
135 unsigned short adc_reg[STAGE_NUM];
136 unsigned short amb_reg[STAGE_NUM];
137 unsigned short sensor_val[STAGE_NUM];
138
139 struct ad714x_platform_data *hw;
140 struct ad714x_driver_data *sw;
141
142 int irq;
143 struct device *dev;
144 ad714x_read_t read;
145 ad714x_write_t write;
146
147 struct mutex mutex;
148
149 unsigned product;
150 unsigned version;
151};
152
153static void ad714x_use_com_int(struct ad714x_chip *ad714x,
154 int start_stage, int end_stage)
155{
156 unsigned short data;
157 unsigned short mask;
158
159 mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
160
161 ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
162 data |= 1 << start_stage;
163 ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
164
165 ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
166 data &= ~mask;
167 ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
168}
169
170static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
171 int start_stage, int end_stage)
172{
173 unsigned short data;
174 unsigned short mask;
175
176 mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
177
178 ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
179 data &= ~(1 << start_stage);
180 ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
181
182 ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
183 data |= mask;
184 ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
185}
186
187static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
188 int start_stage, int end_stage)
189{
190 int max_res = 0;
191 int max_idx = 0;
192 int i;
193
194 for (i = start_stage; i <= end_stage; i++) {
195 if (ad714x->sensor_val[i] > max_res) {
196 max_res = ad714x->sensor_val[i];
197 max_idx = i;
198 }
199 }
200
201 return max_idx;
202}
203
204static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x,
205 int start_stage, int end_stage,
206 int highest_stage, int max_coord)
207{
208 int a_param, b_param;
209
210 if (highest_stage == start_stage) {
211 a_param = ad714x->sensor_val[start_stage + 1];
212 b_param = ad714x->sensor_val[start_stage] +
213 ad714x->sensor_val[start_stage + 1];
214 } else if (highest_stage == end_stage) {
215 a_param = ad714x->sensor_val[end_stage] *
216 (end_stage - start_stage) +
217 ad714x->sensor_val[end_stage - 1] *
218 (end_stage - start_stage - 1);
219 b_param = ad714x->sensor_val[end_stage] +
220 ad714x->sensor_val[end_stage - 1];
221 } else {
222 a_param = ad714x->sensor_val[highest_stage] *
223 (highest_stage - start_stage) +
224 ad714x->sensor_val[highest_stage - 1] *
225 (highest_stage - start_stage - 1) +
226 ad714x->sensor_val[highest_stage + 1] *
227 (highest_stage - start_stage + 1);
228 b_param = ad714x->sensor_val[highest_stage] +
229 ad714x->sensor_val[highest_stage - 1] +
230 ad714x->sensor_val[highest_stage + 1];
231 }
232
233 return (max_coord / (end_stage - start_stage)) * a_param / b_param;
234}
235
236/*
237 * One button can connect to multi positive and negative of CDCs
238 * Multi-buttons can connect to same positive/negative of one CDC
239 */
240static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
241{
242 struct ad714x_button_plat *hw = &ad714x->hw->button[idx];
243 struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
244
245 switch (sw->state) {
246 case IDLE:
247 if (((ad714x->h_state & hw->h_mask) == hw->h_mask) &&
248 ((ad714x->l_state & hw->l_mask) == hw->l_mask)) {
249 dev_dbg(ad714x->dev, "button %d touched\n", idx);
250 input_report_key(sw->input, hw->keycode, 1);
251 input_sync(sw->input);
252 sw->state = ACTIVE;
253 }
254 break;
255
256 case ACTIVE:
257 if (((ad714x->h_state & hw->h_mask) != hw->h_mask) ||
258 ((ad714x->l_state & hw->l_mask) != hw->l_mask)) {
259 dev_dbg(ad714x->dev, "button %d released\n", idx);
260 input_report_key(sw->input, hw->keycode, 0);
261 input_sync(sw->input);
262 sw->state = IDLE;
263 }
264 break;
265
266 default:
267 break;
268 }
269}
270
271/*
272 * The response of a sensor is defined by the absolute number of codes
273 * between the current CDC value and the ambient value.
274 */
275static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
276{
277 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
278 int i;
279
280 for (i = hw->start_stage; i <= hw->end_stage; i++) {
281 ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
282 &ad714x->adc_reg[i]);
283 ad714x->read(ad714x->dev,
284 STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
285 &ad714x->amb_reg[i]);
286
287 ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] -
288 ad714x->amb_reg[i]);
289 }
290}
291
292static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
293{
294 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
295 struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
296
297 sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
298 hw->end_stage);
299
300 dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx,
301 sw->highest_stage);
302}
303
304/*
305 * The formulae are very straight forward. It uses the sensor with the
306 * highest response and the 2 adjacent ones.
307 * When Sensor 0 has the highest response, only sensor 0 and sensor 1
308 * are used in the calculations. Similarly when the last sensor has the
309 * highest response, only the last sensor and the second last sensors
310 * are used in the calculations.
311 *
312 * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1
313 * v += Sensor response(i)*i
314 * w += Sensor response(i)
315 * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
316 */
317static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
318{
319 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
320 struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
321
322 sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage,
323 sw->highest_stage, hw->max_coord);
324
325 dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx,
326 sw->abs_pos);
327}
328
329/*
330 * To minimise the Impact of the noise on the algorithm, ADI developed a
331 * routine that filters the CDC results after they have been read by the
332 * host processor.
333 * The filter used is an Infinite Input Response(IIR) filter implemented
334 * in firmware and attenuates the noise on the CDC results after they've
335 * been read by the host processor.
336 * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) +
337 * Latest_CDC_result * Coefficient)/10
338 */
339static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
340{
341 struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
342
343 sw->flt_pos = (sw->flt_pos * (10 - 4) +
344 sw->abs_pos * 4)/10;
345
346 dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx,
347 sw->flt_pos);
348}
349
350static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx)
351{
352 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
353
354 ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
355}
356
357static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx)
358{
359 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
360
361 ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
362}
363
364static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
365{
366 struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
367 struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
368 unsigned short h_state, c_state;
369 unsigned short mask;
370
371 mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
372
373 h_state = ad714x->h_state & mask;
374 c_state = ad714x->c_state & mask;
375
376 switch (sw->state) {
377 case IDLE:
378 if (h_state) {
379 sw->state = JITTER;
380 /* In End of Conversion interrupt mode, the AD714X
381 * continuously generates hardware interrupts.
382 */
383 ad714x_slider_use_com_int(ad714x, idx);
384 dev_dbg(ad714x->dev, "slider %d touched\n", idx);
385 }
386 break;
387
388 case JITTER:
389 if (c_state == mask) {
390 ad714x_slider_cal_sensor_val(ad714x, idx);
391 ad714x_slider_cal_highest_stage(ad714x, idx);
392 ad714x_slider_cal_abs_pos(ad714x, idx);
393 sw->flt_pos = sw->abs_pos;
394 sw->state = ACTIVE;
395 }
396 break;
397
398 case ACTIVE:
399 if (c_state == mask) {
400 if (h_state) {
401 ad714x_slider_cal_sensor_val(ad714x, idx);
402 ad714x_slider_cal_highest_stage(ad714x, idx);
403 ad714x_slider_cal_abs_pos(ad714x, idx);
404 ad714x_slider_cal_flt_pos(ad714x, idx);
405
406 input_report_abs(sw->input, ABS_X, sw->flt_pos);
407 input_report_key(sw->input, BTN_TOUCH, 1);
408 } else {
409 /* When the user lifts off the sensor, configure
410 * the AD714X back to threshold interrupt mode.
411 */
412 ad714x_slider_use_thr_int(ad714x, idx);
413 sw->state = IDLE;
414 input_report_key(sw->input, BTN_TOUCH, 0);
415 dev_dbg(ad714x->dev, "slider %d released\n",
416 idx);
417 }
418 input_sync(sw->input);
419 }
420 break;
421
422 default:
423 break;
424 }
425}
426
427/*
428 * When the scroll wheel is activated, we compute the absolute position based
429 * on the sensor values. To calculate the position, we first determine the
430 * sensor that has the greatest response among the 8 sensors that constitutes
431 * the scrollwheel. Then we determined the 2 sensors on either sides of the
432 * sensor with the highest response and we apply weights to these sensors.
433 */
434static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
435{
436 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
437 struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
438
439 sw->pre_highest_stage = sw->highest_stage;
440 sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
441 hw->end_stage);
442
443 dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx,
444 sw->highest_stage);
445}
446
447static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
448{
449 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
450 int i;
451
452 for (i = hw->start_stage; i <= hw->end_stage; i++) {
453 ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
454 &ad714x->adc_reg[i]);
455 ad714x->read(ad714x->dev,
456 STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
457 &ad714x->amb_reg[i]);
458 if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
459 ad714x->sensor_val[i] = ad714x->adc_reg[i] -
460 ad714x->amb_reg[i];
461 else
462 ad714x->sensor_val[i] = 0;
463 }
464}
465
466/*
467 * When the scroll wheel is activated, we compute the absolute position based
468 * on the sensor values. To calculate the position, we first determine the
469 * sensor that has the greatest response among the 8 sensors that constitutes
470 * the scrollwheel. Then we determined the 2 sensors on either sides of the
471 * sensor with the highest response and we apply weights to these sensors. The
472 * result of this computation gives us the mean value which defined by the
473 * following formula:
474 * For i= second_before_highest_stage to i= second_after_highest_stage
475 * v += Sensor response(i)*WEIGHT*(i+3)
476 * w += Sensor response(i)
477 * Mean_Value=v/w
478 * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio
479 */
480
481#define WEIGHT_FACTOR 30
482/* This constant prevents the "PositionOffset" from reaching a big value */
483#define OFFSET_POSITION_CLAMP 120
484static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
485{
486 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
487 struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
488 int stage_num = hw->end_stage - hw->start_stage + 1;
489 int second_before, first_before, highest, first_after, second_after;
490 int a_param, b_param;
491
492 /* Calculate Mean value */
493
494 second_before = (sw->highest_stage + stage_num - 2) % stage_num;
495 first_before = (sw->highest_stage + stage_num - 1) % stage_num;
496 highest = sw->highest_stage;
497 first_after = (sw->highest_stage + stage_num + 1) % stage_num;
498 second_after = (sw->highest_stage + stage_num + 2) % stage_num;
499
500 if (((sw->highest_stage - hw->start_stage) > 1) &&
501 ((hw->end_stage - sw->highest_stage) > 1)) {
502 a_param = ad714x->sensor_val[second_before] *
503 (second_before - hw->start_stage + 3) +
504 ad714x->sensor_val[first_before] *
505 (second_before - hw->start_stage + 3) +
506 ad714x->sensor_val[highest] *
507 (second_before - hw->start_stage + 3) +
508 ad714x->sensor_val[first_after] *
509 (first_after - hw->start_stage + 3) +
510 ad714x->sensor_val[second_after] *
511 (second_after - hw->start_stage + 3);
512 } else {
513 a_param = ad714x->sensor_val[second_before] *
514 (second_before - hw->start_stage + 1) +
515 ad714x->sensor_val[first_before] *
516 (second_before - hw->start_stage + 2) +
517 ad714x->sensor_val[highest] *
518 (second_before - hw->start_stage + 3) +
519 ad714x->sensor_val[first_after] *
520 (first_after - hw->start_stage + 4) +
521 ad714x->sensor_val[second_after] *
522 (second_after - hw->start_stage + 5);
523 }
524 a_param *= WEIGHT_FACTOR;
525
526 b_param = ad714x->sensor_val[second_before] +
527 ad714x->sensor_val[first_before] +
528 ad714x->sensor_val[highest] +
529 ad714x->sensor_val[first_after] +
530 ad714x->sensor_val[second_after];
531
532 sw->pre_mean_value = sw->mean_value;
533 sw->mean_value = a_param / b_param;
534
535 /* Calculate the offset */
536
537 if ((sw->pre_highest_stage == hw->end_stage) &&
538 (sw->highest_stage == hw->start_stage))
539 sw->pos_offset = sw->mean_value;
540 else if ((sw->pre_highest_stage == hw->start_stage) &&
541 (sw->highest_stage == hw->end_stage))
542 sw->pos_offset = sw->pre_mean_value;
543
544 if (sw->pos_offset > OFFSET_POSITION_CLAMP)
545 sw->pos_offset = OFFSET_POSITION_CLAMP;
546
547 /* Calculate the mean value without the offset */
548
549 sw->pre_mean_value_no_offset = sw->mean_value_no_offset;
550 sw->mean_value_no_offset = sw->mean_value - sw->pos_offset;
551 if (sw->mean_value_no_offset < 0)
552 sw->mean_value_no_offset = 0;
553
554 /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */
555
556 if ((sw->pre_highest_stage == hw->end_stage) &&
557 (sw->highest_stage == hw->start_stage))
558 sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) /
559 hw->max_coord;
560 else if ((sw->pre_highest_stage == hw->start_stage) &&
561 (sw->highest_stage == hw->end_stage))
562 sw->pos_ratio = (sw->mean_value_no_offset * 100) /
563 hw->max_coord;
564 sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio;
565 if (sw->abs_pos > hw->max_coord)
566 sw->abs_pos = hw->max_coord;
567}
568
569static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
570{
571 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
572 struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
573 if (((sw->pre_highest_stage == hw->end_stage) &&
574 (sw->highest_stage == hw->start_stage)) ||
575 ((sw->pre_highest_stage == hw->start_stage) &&
576 (sw->highest_stage == hw->end_stage)))
577 sw->flt_pos = sw->abs_pos;
578 else
579 sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100;
580
581 if (sw->flt_pos > hw->max_coord)
582 sw->flt_pos = hw->max_coord;
583}
584
585static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx)
586{
587 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
588
589 ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
590}
591
592static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx)
593{
594 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
595
596 ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
597}
598
599static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
600{
601 struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
602 struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
603 unsigned short h_state, c_state;
604 unsigned short mask;
605
606 mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
607
608 h_state = ad714x->h_state & mask;
609 c_state = ad714x->c_state & mask;
610
611 switch (sw->state) {
612 case IDLE:
613 if (h_state) {
614 sw->state = JITTER;
615 /* In End of Conversion interrupt mode, the AD714X
616 * continuously generates hardware interrupts.
617 */
618 ad714x_wheel_use_com_int(ad714x, idx);
619 dev_dbg(ad714x->dev, "wheel %d touched\n", idx);
620 }
621 break;
622
623 case JITTER:
624 if (c_state == mask) {
625 ad714x_wheel_cal_sensor_val(ad714x, idx);
626 ad714x_wheel_cal_highest_stage(ad714x, idx);
627 ad714x_wheel_cal_abs_pos(ad714x, idx);
628 sw->flt_pos = sw->abs_pos;
629 sw->state = ACTIVE;
630 }
631 break;
632
633 case ACTIVE:
634 if (c_state == mask) {
635 if (h_state) {
636 ad714x_wheel_cal_sensor_val(ad714x, idx);
637 ad714x_wheel_cal_highest_stage(ad714x, idx);
638 ad714x_wheel_cal_abs_pos(ad714x, idx);
639 ad714x_wheel_cal_flt_pos(ad714x, idx);
640
641 input_report_abs(sw->input, ABS_WHEEL,
642 sw->abs_pos);
643 input_report_key(sw->input, BTN_TOUCH, 1);
644 } else {
645 /* When the user lifts off the sensor, configure
646 * the AD714X back to threshold interrupt mode.
647 */
648 ad714x_wheel_use_thr_int(ad714x, idx);
649 sw->state = IDLE;
650 input_report_key(sw->input, BTN_TOUCH, 0);
651
652 dev_dbg(ad714x->dev, "wheel %d released\n",
653 idx);
654 }
655 input_sync(sw->input);
656 }
657 break;
658
659 default:
660 break;
661 }
662}
663
664static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
665{
666 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
667 int i;
668
669 for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
670 ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
671 &ad714x->adc_reg[i]);
672 ad714x->read(ad714x->dev,
673 STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
674 &ad714x->amb_reg[i]);
675 if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
676 ad714x->sensor_val[i] = ad714x->adc_reg[i] -
677 ad714x->amb_reg[i];
678 else
679 ad714x->sensor_val[i] = 0;
680 }
681}
682
683static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
684{
685 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
686 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
687
688 sw->x_highest_stage = ad714x_cal_highest_stage(ad714x,
689 hw->x_start_stage, hw->x_end_stage);
690 sw->y_highest_stage = ad714x_cal_highest_stage(ad714x,
691 hw->y_start_stage, hw->y_end_stage);
692
693 dev_dbg(ad714x->dev,
694 "touchpad %d x_highest_stage:%d, y_highest_stage:%d\n",
695 idx, sw->x_highest_stage, sw->y_highest_stage);
696}
697
698/*
699 * If 2 fingers are touching the sensor then 2 peaks can be observed in the
700 * distribution.
701 * The arithmetic doesn't support to get absolute coordinates for multi-touch
702 * yet.
703 */
704static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
705{
706 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
707 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
708 int i;
709
710 for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) {
711 if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
712 > (ad714x->sensor_val[i + 1] / 10))
713 return 1;
714 }
715
716 for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) {
717 if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
718 > (ad714x->sensor_val[i] / 10))
719 return 1;
720 }
721
722 for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) {
723 if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
724 > (ad714x->sensor_val[i + 1] / 10))
725 return 1;
726 }
727
728 for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) {
729 if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
730 > (ad714x->sensor_val[i] / 10))
731 return 1;
732 }
733
734 return 0;
735}
736
737/*
738 * If only one finger is used to activate the touch pad then only 1 peak will be
739 * registered in the distribution. This peak and the 2 adjacent sensors will be
740 * used in the calculation of the absolute position. This will prevent hand
741 * shadows to affect the absolute position calculation.
742 */
743static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
744{
745 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
746 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
747
748 sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage,
749 hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord);
750 sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage,
751 hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord);
752
753 dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx,
754 sw->x_abs_pos, sw->y_abs_pos);
755}
756
757static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
758{
759 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
760
761 sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) +
762 sw->x_abs_pos * 4)/10;
763 sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) +
764 sw->y_abs_pos * 4)/10;
765
766 dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n",
767 idx, sw->x_flt_pos, sw->y_flt_pos);
768}
769
770/*
771 * To prevent distortion from showing in the absolute position, it is
772 * necessary to detect the end points. When endpoints are detected, the
773 * driver stops updating the status variables with absolute positions.
774 * End points are detected on the 4 edges of the touchpad sensor. The
775 * method to detect them is the same for all 4.
776 * To detect the end points, the firmware computes the difference in
777 * percent between the sensor on the edge and the adjacent one. The
778 * difference is calculated in percent in order to make the end point
779 * detection independent of the pressure.
780 */
781
782#define LEFT_END_POINT_DETECTION_LEVEL 550
783#define RIGHT_END_POINT_DETECTION_LEVEL 750
784#define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL 850
785#define TOP_END_POINT_DETECTION_LEVEL 550
786#define BOTTOM_END_POINT_DETECTION_LEVEL 950
787#define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL 700
788static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx)
789{
790 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
791 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
792 int percent_sensor_diff;
793
794 /* left endpoint detect */
795 percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] -
796 ad714x->sensor_val[hw->x_start_stage + 1]) * 100 /
797 ad714x->sensor_val[hw->x_start_stage + 1];
798 if (!sw->left_ep) {
799 if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL) {
800 sw->left_ep = 1;
801 sw->left_ep_val =
802 ad714x->sensor_val[hw->x_start_stage + 1];
803 }
804 } else {
805 if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) &&
806 (ad714x->sensor_val[hw->x_start_stage + 1] >
807 LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val))
808 sw->left_ep = 0;
809 }
810
811 /* right endpoint detect */
812 percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] -
813 ad714x->sensor_val[hw->x_end_stage - 1]) * 100 /
814 ad714x->sensor_val[hw->x_end_stage - 1];
815 if (!sw->right_ep) {
816 if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL) {
817 sw->right_ep = 1;
818 sw->right_ep_val =
819 ad714x->sensor_val[hw->x_end_stage - 1];
820 }
821 } else {
822 if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) &&
823 (ad714x->sensor_val[hw->x_end_stage - 1] >
824 LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val))
825 sw->right_ep = 0;
826 }
827
828 /* top endpoint detect */
829 percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] -
830 ad714x->sensor_val[hw->y_start_stage + 1]) * 100 /
831 ad714x->sensor_val[hw->y_start_stage + 1];
832 if (!sw->top_ep) {
833 if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL) {
834 sw->top_ep = 1;
835 sw->top_ep_val =
836 ad714x->sensor_val[hw->y_start_stage + 1];
837 }
838 } else {
839 if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) &&
840 (ad714x->sensor_val[hw->y_start_stage + 1] >
841 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val))
842 sw->top_ep = 0;
843 }
844
845 /* bottom endpoint detect */
846 percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] -
847 ad714x->sensor_val[hw->y_end_stage - 1]) * 100 /
848 ad714x->sensor_val[hw->y_end_stage - 1];
849 if (!sw->bottom_ep) {
850 if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL) {
851 sw->bottom_ep = 1;
852 sw->bottom_ep_val =
853 ad714x->sensor_val[hw->y_end_stage - 1];
854 }
855 } else {
856 if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) &&
857 (ad714x->sensor_val[hw->y_end_stage - 1] >
858 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val))
859 sw->bottom_ep = 0;
860 }
861
862 return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep;
863}
864
865static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx)
866{
867 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
868
869 ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage);
870}
871
872static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx)
873{
874 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
875
876 ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage);
877 ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage);
878}
879
880static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx)
881{
882 struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
883 struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
884 unsigned short h_state, c_state;
885 unsigned short mask;
886
887 mask = (((1 << (hw->x_end_stage + 1)) - 1) -
888 ((1 << hw->x_start_stage) - 1)) +
889 (((1 << (hw->y_end_stage + 1)) - 1) -
890 ((1 << hw->y_start_stage) - 1));
891
892 h_state = ad714x->h_state & mask;
893 c_state = ad714x->c_state & mask;
894
895 switch (sw->state) {
896 case IDLE:
897 if (h_state) {
898 sw->state = JITTER;
899 /* In End of Conversion interrupt mode, the AD714X
900 * continuously generates hardware interrupts.
901 */
902 touchpad_use_com_int(ad714x, idx);
903 dev_dbg(ad714x->dev, "touchpad %d touched\n", idx);
904 }
905 break;
906
907 case JITTER:
908 if (c_state == mask) {
909 touchpad_cal_sensor_val(ad714x, idx);
910 touchpad_cal_highest_stage(ad714x, idx);
911 if ((!touchpad_check_second_peak(ad714x, idx)) &&
912 (!touchpad_check_endpoint(ad714x, idx))) {
913 dev_dbg(ad714x->dev,
914 "touchpad%d, 2 fingers or endpoint\n",
915 idx);
916 touchpad_cal_abs_pos(ad714x, idx);
917 sw->x_flt_pos = sw->x_abs_pos;
918 sw->y_flt_pos = sw->y_abs_pos;
919 sw->state = ACTIVE;
920 }
921 }
922 break;
923
924 case ACTIVE:
925 if (c_state == mask) {
926 if (h_state) {
927 touchpad_cal_sensor_val(ad714x, idx);
928 touchpad_cal_highest_stage(ad714x, idx);
929 if ((!touchpad_check_second_peak(ad714x, idx))
930 && (!touchpad_check_endpoint(ad714x, idx))) {
931 touchpad_cal_abs_pos(ad714x, idx);
932 touchpad_cal_flt_pos(ad714x, idx);
933 input_report_abs(sw->input, ABS_X,
934 sw->x_flt_pos);
935 input_report_abs(sw->input, ABS_Y,
936 sw->y_flt_pos);
937 input_report_key(sw->input, BTN_TOUCH,
938 1);
939 }
940 } else {
941 /* When the user lifts off the sensor, configure
942 * the AD714X back to threshold interrupt mode.
943 */
944 touchpad_use_thr_int(ad714x, idx);
945 sw->state = IDLE;
946 input_report_key(sw->input, BTN_TOUCH, 0);
947 dev_dbg(ad714x->dev, "touchpad %d released\n",
948 idx);
949 }
950 input_sync(sw->input);
951 }
952 break;
953
954 default:
955 break;
956 }
957}
958
959static int ad714x_hw_detect(struct ad714x_chip *ad714x)
960{
961 unsigned short data;
962
963 ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data);
964 switch (data & 0xFFF0) {
965 case AD7147_PARTID:
966 ad714x->product = 0x7147;
967 ad714x->version = data & 0xF;
968 dev_info(ad714x->dev, "found AD7147 captouch, rev:%d\n",
969 ad714x->version);
970 return 0;
971
972 case AD7142_PARTID:
973 ad714x->product = 0x7142;
974 ad714x->version = data & 0xF;
975 dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n",
976 ad714x->version);
977 return 0;
978
979 default:
980 dev_err(ad714x->dev,
981 "fail to detect AD714X captouch, read ID is %04x\n",
982 data);
983 return -ENODEV;
984 }
985}
986
987static void ad714x_hw_init(struct ad714x_chip *ad714x)
988{
989 int i, j;
990 unsigned short reg_base;
991 unsigned short data;
992
993 /* configuration CDC and interrupts */
994
995 for (i = 0; i < STAGE_NUM; i++) {
996 reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
997 for (j = 0; j < STAGE_CFGREG_NUM; j++)
998 ad714x->write(ad714x->dev, reg_base + j,
999 ad714x->hw->stage_cfg_reg[i][j]);
1000 }
1001
1002 for (i = 0; i < SYS_CFGREG_NUM; i++)
1003 ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i,
1004 ad714x->hw->sys_cfg_reg[i]);
1005 for (i = 0; i < SYS_CFGREG_NUM; i++)
1006 ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i,
1007 &data);
1008
1009 ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF);
1010
1011 /* clear all interrupts */
1012 ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
1013 ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
1014 ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
1015}
1016
1017static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
1018{
1019 struct ad714x_chip *ad714x = data;
1020 int i;
1021
1022 mutex_lock(&ad714x->mutex);
1023
1024 ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state);
1025 ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state);
1026 ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state);
1027
1028 for (i = 0; i < ad714x->hw->button_num; i++)
1029 ad714x_button_state_machine(ad714x, i);
1030 for (i = 0; i < ad714x->hw->slider_num; i++)
1031 ad714x_slider_state_machine(ad714x, i);
1032 for (i = 0; i < ad714x->hw->wheel_num; i++)
1033 ad714x_wheel_state_machine(ad714x, i);
1034 for (i = 0; i < ad714x->hw->touchpad_num; i++)
1035 ad714x_touchpad_state_machine(ad714x, i);
1036
1037 mutex_unlock(&ad714x->mutex);
1038
1039 return IRQ_HANDLED;
1040}
1041
1042#define MAX_DEVICE_NUM 8
1043struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
1044 ad714x_read_t read, ad714x_write_t write)
1045{
1046 int i, alloc_idx;
1047 int error;
1048 struct input_dev *input[MAX_DEVICE_NUM];
1049
1050 struct ad714x_platform_data *plat_data = dev->platform_data;
1051 struct ad714x_chip *ad714x;
1052 void *drv_mem;
1053
1054 struct ad714x_button_drv *bt_drv;
1055 struct ad714x_slider_drv *sd_drv;
1056 struct ad714x_wheel_drv *wl_drv;
1057 struct ad714x_touchpad_drv *tp_drv;
1058
1059
1060 if (irq <= 0) {
1061 dev_err(dev, "IRQ not configured!\n");
1062 error = -EINVAL;
1063 goto err_out;
1064 }
1065
1066 if (dev->platform_data == NULL) {
1067 dev_err(dev, "platform data for ad714x doesn't exist\n");
1068 error = -EINVAL;
1069 goto err_out;
1070 }
1071
1072 ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) +
1073 sizeof(*sd_drv) * plat_data->slider_num +
1074 sizeof(*wl_drv) * plat_data->wheel_num +
1075 sizeof(*tp_drv) * plat_data->touchpad_num +
1076 sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL);
1077 if (!ad714x) {
1078 error = -ENOMEM;
1079 goto err_out;
1080 }
1081
1082 ad714x->hw = plat_data;
1083
1084 drv_mem = ad714x + 1;
1085 ad714x->sw = drv_mem;
1086 drv_mem += sizeof(*ad714x->sw);
1087 ad714x->sw->slider = sd_drv = drv_mem;
1088 drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num;
1089 ad714x->sw->wheel = wl_drv = drv_mem;
1090 drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num;
1091 ad714x->sw->touchpad = tp_drv = drv_mem;
1092 drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num;
1093 ad714x->sw->button = bt_drv = drv_mem;
1094 drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num;
1095
1096 ad714x->read = read;
1097 ad714x->write = write;
1098 ad714x->irq = irq;
1099 ad714x->dev = dev;
1100
1101 error = ad714x_hw_detect(ad714x);
1102 if (error)
1103 goto err_free_mem;
1104
1105 /* initilize and request sw/hw resources */
1106
1107 ad714x_hw_init(ad714x);
1108 mutex_init(&ad714x->mutex);
1109
1110 /*
1111 * Allocate and register AD714X input device
1112 */
1113 alloc_idx = 0;
1114
1115 /* a slider uses one input_dev instance */
1116 if (ad714x->hw->slider_num > 0) {
1117 struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
1118
1119 for (i = 0; i < ad714x->hw->slider_num; i++) {
1120 sd_drv[i].input = input[alloc_idx] = input_allocate_device();
1121 if (!input[alloc_idx]) {
1122 error = -ENOMEM;
1123 goto err_free_dev;
1124 }
1125
1126 __set_bit(EV_ABS, input[alloc_idx]->evbit);
1127 __set_bit(EV_KEY, input[alloc_idx]->evbit);
1128 __set_bit(ABS_X, input[alloc_idx]->absbit);
1129 __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
1130 input_set_abs_params(input[alloc_idx],
1131 ABS_X, 0, sd_plat->max_coord, 0, 0);
1132
1133 input[alloc_idx]->id.bustype = bus_type;
1134 input[alloc_idx]->id.product = ad714x->product;
1135 input[alloc_idx]->id.version = ad714x->version;
1136
1137 error = input_register_device(input[alloc_idx]);
1138 if (error)
1139 goto err_free_dev;
1140
1141 alloc_idx++;
1142 }
1143 }
1144
1145 /* a wheel uses one input_dev instance */
1146 if (ad714x->hw->wheel_num > 0) {
1147 struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
1148
1149 for (i = 0; i < ad714x->hw->wheel_num; i++) {
1150 wl_drv[i].input = input[alloc_idx] = input_allocate_device();
1151 if (!input[alloc_idx]) {
1152 error = -ENOMEM;
1153 goto err_free_dev;
1154 }
1155
1156 __set_bit(EV_KEY, input[alloc_idx]->evbit);
1157 __set_bit(EV_ABS, input[alloc_idx]->evbit);
1158 __set_bit(ABS_WHEEL, input[alloc_idx]->absbit);
1159 __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
1160 input_set_abs_params(input[alloc_idx],
1161 ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
1162
1163 input[alloc_idx]->id.bustype = bus_type;
1164 input[alloc_idx]->id.product = ad714x->product;
1165 input[alloc_idx]->id.version = ad714x->version;
1166
1167 error = input_register_device(input[alloc_idx]);
1168 if (error)
1169 goto err_free_dev;
1170
1171 alloc_idx++;
1172 }
1173 }
1174
1175 /* a touchpad uses one input_dev instance */
1176 if (ad714x->hw->touchpad_num > 0) {
1177 struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
1178
1179 for (i = 0; i < ad714x->hw->touchpad_num; i++) {
1180 tp_drv[i].input = input[alloc_idx] = input_allocate_device();
1181 if (!input[alloc_idx]) {
1182 error = -ENOMEM;
1183 goto err_free_dev;
1184 }
1185
1186 __set_bit(EV_ABS, input[alloc_idx]->evbit);
1187 __set_bit(EV_KEY, input[alloc_idx]->evbit);
1188 __set_bit(ABS_X, input[alloc_idx]->absbit);
1189 __set_bit(ABS_Y, input[alloc_idx]->absbit);
1190 __set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
1191 input_set_abs_params(input[alloc_idx],
1192 ABS_X, 0, tp_plat->x_max_coord, 0, 0);
1193 input_set_abs_params(input[alloc_idx],
1194 ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
1195
1196 input[alloc_idx]->id.bustype = bus_type;
1197 input[alloc_idx]->id.product = ad714x->product;
1198 input[alloc_idx]->id.version = ad714x->version;
1199
1200 error = input_register_device(input[alloc_idx]);
1201 if (error)
1202 goto err_free_dev;
1203
1204 alloc_idx++;
1205 }
1206 }
1207
1208 /* all buttons use one input node */
1209 if (ad714x->hw->button_num > 0) {
1210 struct ad714x_button_plat *bt_plat = ad714x->hw->button;
1211
1212 input[alloc_idx] = input_allocate_device();
1213 if (!input[alloc_idx]) {
1214 error = -ENOMEM;
1215 goto err_free_dev;
1216 }
1217
1218 __set_bit(EV_KEY, input[alloc_idx]->evbit);
1219 for (i = 0; i < ad714x->hw->button_num; i++) {
1220 bt_drv[i].input = input[alloc_idx];
1221 __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit);
1222 }
1223
1224 input[alloc_idx]->id.bustype = bus_type;
1225 input[alloc_idx]->id.product = ad714x->product;
1226 input[alloc_idx]->id.version = ad714x->version;
1227
1228 error = input_register_device(input[alloc_idx]);
1229 if (error)
1230 goto err_free_dev;
1231
1232 alloc_idx++;
1233 }
1234
1235 error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
1236 IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x);
1237 if (error) {
1238 dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
1239 goto err_unreg_dev;
1240 }
1241
1242 return ad714x;
1243
1244 err_free_dev:
1245 dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx);
1246 input_free_device(input[alloc_idx]);
1247 err_unreg_dev:
1248 while (--alloc_idx >= 0)
1249 input_unregister_device(input[alloc_idx]);
1250 err_free_mem:
1251 kfree(ad714x);
1252 err_out:
1253 return ERR_PTR(error);
1254}
1255EXPORT_SYMBOL(ad714x_probe);
1256
1257void ad714x_remove(struct ad714x_chip *ad714x)
1258{
1259 struct ad714x_platform_data *hw = ad714x->hw;
1260 struct ad714x_driver_data *sw = ad714x->sw;
1261 int i;
1262
1263 free_irq(ad714x->irq, ad714x);
1264
1265 /* unregister and free all input devices */
1266
1267 for (i = 0; i < hw->slider_num; i++)
1268 input_unregister_device(sw->slider[i].input);
1269
1270 for (i = 0; i < hw->wheel_num; i++)
1271 input_unregister_device(sw->wheel[i].input);
1272
1273 for (i = 0; i < hw->touchpad_num; i++)
1274 input_unregister_device(sw->touchpad[i].input);
1275
1276 if (hw->button_num)
1277 input_unregister_device(sw->button[0].input);
1278
1279 kfree(ad714x);
1280}
1281EXPORT_SYMBOL(ad714x_remove);
1282
1283#ifdef CONFIG_PM
1284int ad714x_disable(struct ad714x_chip *ad714x)
1285{
1286 unsigned short data;
1287
1288 dev_dbg(ad714x->dev, "%s enter\n", __func__);
1289
1290 mutex_lock(&ad714x->mutex);
1291
1292 data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
1293 ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data);
1294
1295 mutex_unlock(&ad714x->mutex);
1296
1297 return 0;
1298}
1299EXPORT_SYMBOL(ad714x_disable);
1300
1301int ad714x_enable(struct ad714x_chip *ad714x)
1302{
1303 unsigned short data;
1304
1305 dev_dbg(ad714x->dev, "%s enter\n", __func__);
1306
1307 mutex_lock(&ad714x->mutex);
1308
1309 /* resume to non-shutdown mode */
1310
1311 ad714x->write(ad714x->dev, AD714X_PWR_CTRL,
1312 ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
1313
1314 /* make sure the interrupt output line is not low level after resume,
1315 * otherwise we will get no chance to enter falling-edge irq again
1316 */
1317
1318 ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
1319 ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
1320 ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
1321
1322 mutex_unlock(&ad714x->mutex);
1323
1324 return 0;
1325}
1326EXPORT_SYMBOL(ad714x_enable);
1327#endif
1328
1329MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
1330MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
1331MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
new file mode 100644
index 000000000000..45c54fb13f07
--- /dev/null
+++ b/drivers/input/misc/ad714x.h
@@ -0,0 +1,26 @@
1/*
2 * AD714X CapTouch Programmable Controller driver (bus interfaces)
3 *
4 * Copyright 2009 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#ifndef _AD714X_H_
10#define _AD714X_H_
11
12#include <linux/types.h>
13
14struct device;
15struct ad714x_chip;
16
17typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *);
18typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short);
19
20int ad714x_disable(struct ad714x_chip *ad714x);
21int ad714x_enable(struct ad714x_chip *ad714x);
22struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
23 ad714x_read_t read, ad714x_write_t write);
24void ad714x_remove(struct ad714x_chip *ad714x);
25
26#endif