diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-06-18 20:25:08 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-06-18 20:25:08 -0400 |
commit | 6ea24cf79e055f0a62a64baa8587e2254a493c7b (patch) | |
tree | c5cd6113ed93854b1bc30cd471c366f080c4be2f /drivers/input | |
parent | 540c26087bfbad6ea72758b76b16ae6282a73fea (diff) | |
parent | 488326947cd1f038da8d2c9068a0d07b913b7983 (diff) |
Merge branch 'cec-defines' into for-linus
Let's bring in HDMI CEC defines to ease merging CEC support in the next
merge window.
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input-compat.c | 6 | ||||
-rw-r--r-- | drivers/input/input-compat.h | 14 | ||||
-rw-r--r-- | drivers/input/input.c | 2 | ||||
-rw-r--r-- | drivers/input/misc/uinput.c | 4 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/fsl-imx25-tcq.c | 596 | ||||
-rw-r--r-- | drivers/input/touchscreen/wdt87xx_i2c.c | 2 |
8 files changed, 614 insertions, 20 deletions
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index 64ca7113ff28..d84d20b9cec0 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c | |||
@@ -17,7 +17,7 @@ | |||
17 | int input_event_from_user(const char __user *buffer, | 17 | int input_event_from_user(const char __user *buffer, |
18 | struct input_event *event) | 18 | struct input_event *event) |
19 | { | 19 | { |
20 | if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) { | 20 | if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { |
21 | struct input_event_compat compat_event; | 21 | struct input_event_compat compat_event; |
22 | 22 | ||
23 | if (copy_from_user(&compat_event, buffer, | 23 | if (copy_from_user(&compat_event, buffer, |
@@ -41,7 +41,7 @@ int input_event_from_user(const char __user *buffer, | |||
41 | int input_event_to_user(char __user *buffer, | 41 | int input_event_to_user(char __user *buffer, |
42 | const struct input_event *event) | 42 | const struct input_event *event) |
43 | { | 43 | { |
44 | if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) { | 44 | if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { |
45 | struct input_event_compat compat_event; | 45 | struct input_event_compat compat_event; |
46 | 46 | ||
47 | compat_event.time.tv_sec = event->time.tv_sec; | 47 | compat_event.time.tv_sec = event->time.tv_sec; |
@@ -65,7 +65,7 @@ int input_event_to_user(char __user *buffer, | |||
65 | int input_ff_effect_from_user(const char __user *buffer, size_t size, | 65 | int input_ff_effect_from_user(const char __user *buffer, size_t size, |
66 | struct ff_effect *effect) | 66 | struct ff_effect *effect) |
67 | { | 67 | { |
68 | if (INPUT_COMPAT_TEST) { | 68 | if (in_compat_syscall()) { |
69 | struct ff_effect_compat *compat_effect; | 69 | struct ff_effect_compat *compat_effect; |
70 | 70 | ||
71 | if (size != sizeof(struct ff_effect_compat)) | 71 | if (size != sizeof(struct ff_effect_compat)) |
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h index 148f66fe3205..1563160a7af3 100644 --- a/drivers/input/input-compat.h +++ b/drivers/input/input-compat.h | |||
@@ -17,18 +17,6 @@ | |||
17 | 17 | ||
18 | #ifdef CONFIG_COMPAT | 18 | #ifdef CONFIG_COMPAT |
19 | 19 | ||
20 | /* Note to the author of this code: did it ever occur to | ||
21 | you why the ifdefs are needed? Think about it again. -AK */ | ||
22 | #if defined(CONFIG_X86_64) || defined(CONFIG_TILE) | ||
23 | # define INPUT_COMPAT_TEST is_compat_task() | ||
24 | #elif defined(CONFIG_S390) | ||
25 | # define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT) | ||
26 | #elif defined(CONFIG_MIPS) | ||
27 | # define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR) | ||
28 | #else | ||
29 | # define INPUT_COMPAT_TEST test_thread_flag(TIF_32BIT) | ||
30 | #endif | ||
31 | |||
32 | struct input_event_compat { | 20 | struct input_event_compat { |
33 | struct compat_timeval time; | 21 | struct compat_timeval time; |
34 | __u16 type; | 22 | __u16 type; |
@@ -67,7 +55,7 @@ struct ff_effect_compat { | |||
67 | 55 | ||
68 | static inline size_t input_event_size(void) | 56 | static inline size_t input_event_size(void) |
69 | { | 57 | { |
70 | return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ? | 58 | return (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) ? |
71 | sizeof(struct input_event_compat) : sizeof(struct input_event); | 59 | sizeof(struct input_event_compat) : sizeof(struct input_event); |
72 | } | 60 | } |
73 | 61 | ||
diff --git a/drivers/input/input.c b/drivers/input/input.c index 880605959aa6..b87ffbd4547d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
@@ -1015,7 +1015,7 @@ static int input_bits_to_string(char *buf, int buf_size, | |||
1015 | { | 1015 | { |
1016 | int len = 0; | 1016 | int len = 0; |
1017 | 1017 | ||
1018 | if (INPUT_COMPAT_TEST) { | 1018 | if (in_compat_syscall()) { |
1019 | u32 dword = bits >> 32; | 1019 | u32 dword = bits >> 32; |
1020 | if (dword || !skip_empty) | 1020 | if (dword || !skip_empty) |
1021 | len += snprintf(buf, buf_size, "%x ", dword); | 1021 | len += snprintf(buf, buf_size, "%x ", dword); |
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 79338f4bdecb..65ebbd111702 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c | |||
@@ -664,7 +664,7 @@ struct uinput_ff_upload_compat { | |||
664 | static int uinput_ff_upload_to_user(char __user *buffer, | 664 | static int uinput_ff_upload_to_user(char __user *buffer, |
665 | const struct uinput_ff_upload *ff_up) | 665 | const struct uinput_ff_upload *ff_up) |
666 | { | 666 | { |
667 | if (INPUT_COMPAT_TEST) { | 667 | if (in_compat_syscall()) { |
668 | struct uinput_ff_upload_compat ff_up_compat; | 668 | struct uinput_ff_upload_compat ff_up_compat; |
669 | 669 | ||
670 | ff_up_compat.request_id = ff_up->request_id; | 670 | ff_up_compat.request_id = ff_up->request_id; |
@@ -695,7 +695,7 @@ static int uinput_ff_upload_to_user(char __user *buffer, | |||
695 | static int uinput_ff_upload_from_user(const char __user *buffer, | 695 | static int uinput_ff_upload_from_user(const char __user *buffer, |
696 | struct uinput_ff_upload *ff_up) | 696 | struct uinput_ff_upload *ff_up) |
697 | { | 697 | { |
698 | if (INPUT_COMPAT_TEST) { | 698 | if (in_compat_syscall()) { |
699 | struct uinput_ff_upload_compat ff_up_compat; | 699 | struct uinput_ff_upload_compat ff_up_compat; |
700 | 700 | ||
701 | if (copy_from_user(&ff_up_compat, buffer, | 701 | if (copy_from_user(&ff_up_compat, buffer, |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1f99e7f30e27..8ecdc38fd489 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -833,6 +833,15 @@ config TOUCHSCREEN_USB_COMPOSITE | |||
833 | To compile this driver as a module, choose M here: the | 833 | To compile this driver as a module, choose M here: the |
834 | module will be called usbtouchscreen. | 834 | module will be called usbtouchscreen. |
835 | 835 | ||
836 | config TOUCHSCREEN_MX25 | ||
837 | tristate "Freescale i.MX25 touchscreen input driver" | ||
838 | depends on MFD_MX25_TSADC | ||
839 | help | ||
840 | Enable support for touchscreen connected to your i.MX25. | ||
841 | |||
842 | To compile this driver as a module, choose M here: the | ||
843 | module will be called fsl-imx25-tcq. | ||
844 | |||
836 | config TOUCHSCREEN_MC13783 | 845 | config TOUCHSCREEN_MC13783 |
837 | tristate "Freescale MC13783 touchscreen input driver" | 846 | tristate "Freescale MC13783 touchscreen input driver" |
838 | depends on MFD_MC13XXX | 847 | depends on MFD_MC13XXX |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 4b518c76e0d7..f42975e719e0 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -46,6 +46,7 @@ obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o | |||
46 | obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o | 46 | obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o |
47 | obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o | 47 | obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o |
48 | obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o | 48 | obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o |
49 | obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o | ||
49 | obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o | 50 | obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o |
50 | obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o | 51 | obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o |
51 | obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o | 52 | obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o |
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c new file mode 100644 index 000000000000..fe9877a6af9e --- /dev/null +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it under | ||
5 | * the terms of the GNU General Public License version 2 as published by the | ||
6 | * Free Software Foundation. | ||
7 | * | ||
8 | * Based on driver from 2011: | ||
9 | * Juergen Beisert, Pengutronix <kernel@pengutronix.de> | ||
10 | * | ||
11 | * This is the driver for the imx25 TCQ (Touchscreen Conversion Queue) | ||
12 | * connected to the imx25 ADC. | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/input.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/mfd/imx25-tsadc.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/regmap.h> | ||
24 | |||
25 | static const char mx25_tcq_name[] = "mx25-tcq"; | ||
26 | |||
27 | enum mx25_tcq_mode { | ||
28 | MX25_TS_4WIRE, | ||
29 | }; | ||
30 | |||
31 | struct mx25_tcq_priv { | ||
32 | struct regmap *regs; | ||
33 | struct regmap *core_regs; | ||
34 | struct input_dev *idev; | ||
35 | enum mx25_tcq_mode mode; | ||
36 | unsigned int pen_threshold; | ||
37 | unsigned int sample_count; | ||
38 | unsigned int expected_samples; | ||
39 | unsigned int pen_debounce; | ||
40 | unsigned int settling_time; | ||
41 | struct clk *clk; | ||
42 | int irq; | ||
43 | struct device *dev; | ||
44 | }; | ||
45 | |||
46 | static struct regmap_config mx25_tcq_regconfig = { | ||
47 | .fast_io = true, | ||
48 | .max_register = 0x5c, | ||
49 | .reg_bits = 32, | ||
50 | .val_bits = 32, | ||
51 | .reg_stride = 4, | ||
52 | }; | ||
53 | |||
54 | static const struct of_device_id mx25_tcq_ids[] = { | ||
55 | { .compatible = "fsl,imx25-tcq", }, | ||
56 | { /* Sentinel */ } | ||
57 | }; | ||
58 | |||
59 | #define TSC_4WIRE_PRE_INDEX 0 | ||
60 | #define TSC_4WIRE_X_INDEX 1 | ||
61 | #define TSC_4WIRE_Y_INDEX 2 | ||
62 | #define TSC_4WIRE_POST_INDEX 3 | ||
63 | #define TSC_4WIRE_LEAVE 4 | ||
64 | |||
65 | #define MX25_TSC_DEF_THRESHOLD 80 | ||
66 | #define TSC_MAX_SAMPLES 16 | ||
67 | |||
68 | #define MX25_TSC_REPEAT_WAIT 14 | ||
69 | |||
70 | enum mx25_adc_configurations { | ||
71 | MX25_CFG_PRECHARGE = 0, | ||
72 | MX25_CFG_TOUCH_DETECT, | ||
73 | MX25_CFG_X_MEASUREMENT, | ||
74 | MX25_CFG_Y_MEASUREMENT, | ||
75 | }; | ||
76 | |||
77 | #define MX25_PRECHARGE_VALUE (\ | ||
78 | MX25_ADCQ_CFG_YPLL_OFF | \ | ||
79 | MX25_ADCQ_CFG_XNUR_OFF | \ | ||
80 | MX25_ADCQ_CFG_XPUL_HIGH | \ | ||
81 | MX25_ADCQ_CFG_REFP_INT | \ | ||
82 | MX25_ADCQ_CFG_IN_XP | \ | ||
83 | MX25_ADCQ_CFG_REFN_NGND2 | \ | ||
84 | MX25_ADCQ_CFG_IGS) | ||
85 | |||
86 | #define MX25_TOUCH_DETECT_VALUE (\ | ||
87 | MX25_ADCQ_CFG_YNLR | \ | ||
88 | MX25_ADCQ_CFG_YPLL_OFF | \ | ||
89 | MX25_ADCQ_CFG_XNUR_OFF | \ | ||
90 | MX25_ADCQ_CFG_XPUL_OFF | \ | ||
91 | MX25_ADCQ_CFG_REFP_INT | \ | ||
92 | MX25_ADCQ_CFG_IN_XP | \ | ||
93 | MX25_ADCQ_CFG_REFN_NGND2 | \ | ||
94 | MX25_ADCQ_CFG_PENIACK) | ||
95 | |||
96 | static void imx25_setup_queue_cfgs(struct mx25_tcq_priv *priv, | ||
97 | unsigned int settling_cnt) | ||
98 | { | ||
99 | u32 precharge_cfg = | ||
100 | MX25_PRECHARGE_VALUE | | ||
101 | MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt); | ||
102 | u32 touch_detect_cfg = | ||
103 | MX25_TOUCH_DETECT_VALUE | | ||
104 | MX25_ADCQ_CFG_NOS(1) | | ||
105 | MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt); | ||
106 | |||
107 | regmap_write(priv->core_regs, MX25_TSC_TICR, precharge_cfg); | ||
108 | |||
109 | /* PRECHARGE */ | ||
110 | regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_PRECHARGE), | ||
111 | precharge_cfg); | ||
112 | |||
113 | /* TOUCH_DETECT */ | ||
114 | regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_TOUCH_DETECT), | ||
115 | touch_detect_cfg); | ||
116 | |||
117 | /* X Measurement */ | ||
118 | regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_X_MEASUREMENT), | ||
119 | MX25_ADCQ_CFG_YPLL_OFF | | ||
120 | MX25_ADCQ_CFG_XNUR_LOW | | ||
121 | MX25_ADCQ_CFG_XPUL_HIGH | | ||
122 | MX25_ADCQ_CFG_REFP_XP | | ||
123 | MX25_ADCQ_CFG_IN_YP | | ||
124 | MX25_ADCQ_CFG_REFN_XN | | ||
125 | MX25_ADCQ_CFG_NOS(priv->sample_count) | | ||
126 | MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt)); | ||
127 | |||
128 | /* Y Measurement */ | ||
129 | regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_Y_MEASUREMENT), | ||
130 | MX25_ADCQ_CFG_YNLR | | ||
131 | MX25_ADCQ_CFG_YPLL_HIGH | | ||
132 | MX25_ADCQ_CFG_XNUR_OFF | | ||
133 | MX25_ADCQ_CFG_XPUL_OFF | | ||
134 | MX25_ADCQ_CFG_REFP_YP | | ||
135 | MX25_ADCQ_CFG_IN_XP | | ||
136 | MX25_ADCQ_CFG_REFN_YN | | ||
137 | MX25_ADCQ_CFG_NOS(priv->sample_count) | | ||
138 | MX25_ADCQ_CFG_SETTLING_TIME(settling_cnt)); | ||
139 | |||
140 | /* Enable the touch detection right now */ | ||
141 | regmap_write(priv->core_regs, MX25_TSC_TICR, touch_detect_cfg | | ||
142 | MX25_ADCQ_CFG_IGS); | ||
143 | } | ||
144 | |||
145 | static int imx25_setup_queue_4wire(struct mx25_tcq_priv *priv, | ||
146 | unsigned settling_cnt, int *items) | ||
147 | { | ||
148 | imx25_setup_queue_cfgs(priv, settling_cnt); | ||
149 | |||
150 | /* Setup the conversion queue */ | ||
151 | regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0, | ||
152 | MX25_ADCQ_ITEM(0, MX25_CFG_PRECHARGE) | | ||
153 | MX25_ADCQ_ITEM(1, MX25_CFG_TOUCH_DETECT) | | ||
154 | MX25_ADCQ_ITEM(2, MX25_CFG_X_MEASUREMENT) | | ||
155 | MX25_ADCQ_ITEM(3, MX25_CFG_Y_MEASUREMENT) | | ||
156 | MX25_ADCQ_ITEM(4, MX25_CFG_PRECHARGE) | | ||
157 | MX25_ADCQ_ITEM(5, MX25_CFG_TOUCH_DETECT)); | ||
158 | |||
159 | /* | ||
160 | * We measure X/Y with 'sample_count' number of samples and execute a | ||
161 | * touch detection twice, with 1 sample each | ||
162 | */ | ||
163 | priv->expected_samples = priv->sample_count * 2 + 2; | ||
164 | *items = 6; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static void mx25_tcq_disable_touch_irq(struct mx25_tcq_priv *priv) | ||
170 | { | ||
171 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK, | ||
172 | MX25_ADCQ_CR_PDMSK); | ||
173 | } | ||
174 | |||
175 | static void mx25_tcq_enable_touch_irq(struct mx25_tcq_priv *priv) | ||
176 | { | ||
177 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK, 0); | ||
178 | } | ||
179 | |||
180 | static void mx25_tcq_disable_fifo_irq(struct mx25_tcq_priv *priv) | ||
181 | { | ||
182 | regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ, | ||
183 | MX25_ADCQ_MR_FDRY_IRQ); | ||
184 | } | ||
185 | |||
186 | static void mx25_tcq_enable_fifo_irq(struct mx25_tcq_priv *priv) | ||
187 | { | ||
188 | regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ, 0); | ||
189 | } | ||
190 | |||
191 | static void mx25_tcq_force_queue_start(struct mx25_tcq_priv *priv) | ||
192 | { | ||
193 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, | ||
194 | MX25_ADCQ_CR_FQS, | ||
195 | MX25_ADCQ_CR_FQS); | ||
196 | } | ||
197 | |||
198 | static void mx25_tcq_force_queue_stop(struct mx25_tcq_priv *priv) | ||
199 | { | ||
200 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, | ||
201 | MX25_ADCQ_CR_FQS, 0); | ||
202 | } | ||
203 | |||
204 | static void mx25_tcq_fifo_reset(struct mx25_tcq_priv *priv) | ||
205 | { | ||
206 | u32 tcqcr; | ||
207 | |||
208 | regmap_read(priv->regs, MX25_ADCQ_CR, &tcqcr); | ||
209 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST, | ||
210 | MX25_ADCQ_CR_FRST); | ||
211 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST, 0); | ||
212 | regmap_write(priv->regs, MX25_ADCQ_CR, tcqcr); | ||
213 | } | ||
214 | |||
215 | static void mx25_tcq_re_enable_touch_detection(struct mx25_tcq_priv *priv) | ||
216 | { | ||
217 | /* stop the queue from looping */ | ||
218 | mx25_tcq_force_queue_stop(priv); | ||
219 | |||
220 | /* for a clean touch detection, preload the X plane */ | ||
221 | regmap_write(priv->core_regs, MX25_TSC_TICR, MX25_PRECHARGE_VALUE); | ||
222 | |||
223 | /* waste some time now to pre-load the X plate to high voltage */ | ||
224 | mx25_tcq_fifo_reset(priv); | ||
225 | |||
226 | /* re-enable the detection right now */ | ||
227 | regmap_write(priv->core_regs, MX25_TSC_TICR, | ||
228 | MX25_TOUCH_DETECT_VALUE | MX25_ADCQ_CFG_IGS); | ||
229 | |||
230 | regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_PD, | ||
231 | MX25_ADCQ_SR_PD); | ||
232 | |||
233 | /* enable the pen down event to be a source for the interrupt */ | ||
234 | regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_PD_IRQ, 0); | ||
235 | |||
236 | /* lets fire the next IRQ if someone touches the touchscreen */ | ||
237 | mx25_tcq_enable_touch_irq(priv); | ||
238 | } | ||
239 | |||
240 | static void mx25_tcq_create_event_for_4wire(struct mx25_tcq_priv *priv, | ||
241 | u32 *sample_buf, | ||
242 | unsigned int samples) | ||
243 | { | ||
244 | unsigned int x_pos = 0; | ||
245 | unsigned int y_pos = 0; | ||
246 | unsigned int touch_pre = 0; | ||
247 | unsigned int touch_post = 0; | ||
248 | unsigned int i; | ||
249 | |||
250 | for (i = 0; i < samples; i++) { | ||
251 | unsigned int index = MX25_ADCQ_FIFO_ID(sample_buf[i]); | ||
252 | unsigned int val = MX25_ADCQ_FIFO_DATA(sample_buf[i]); | ||
253 | |||
254 | switch (index) { | ||
255 | case 1: | ||
256 | touch_pre = val; | ||
257 | break; | ||
258 | case 2: | ||
259 | x_pos = val; | ||
260 | break; | ||
261 | case 3: | ||
262 | y_pos = val; | ||
263 | break; | ||
264 | case 5: | ||
265 | touch_post = val; | ||
266 | break; | ||
267 | default: | ||
268 | dev_dbg(priv->dev, "Dropped samples because of invalid index %d\n", | ||
269 | index); | ||
270 | return; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | if (samples != 0) { | ||
275 | /* | ||
276 | * only if both touch measures are below a threshold, | ||
277 | * the position is valid | ||
278 | */ | ||
279 | if (touch_pre < priv->pen_threshold && | ||
280 | touch_post < priv->pen_threshold) { | ||
281 | /* valid samples, generate a report */ | ||
282 | x_pos /= priv->sample_count; | ||
283 | y_pos /= priv->sample_count; | ||
284 | input_report_abs(priv->idev, ABS_X, x_pos); | ||
285 | input_report_abs(priv->idev, ABS_Y, y_pos); | ||
286 | input_report_key(priv->idev, BTN_TOUCH, 1); | ||
287 | input_sync(priv->idev); | ||
288 | |||
289 | /* get next sample */ | ||
290 | mx25_tcq_enable_fifo_irq(priv); | ||
291 | } else if (touch_pre >= priv->pen_threshold && | ||
292 | touch_post >= priv->pen_threshold) { | ||
293 | /* | ||
294 | * if both samples are invalid, | ||
295 | * generate a release report | ||
296 | */ | ||
297 | input_report_key(priv->idev, BTN_TOUCH, 0); | ||
298 | input_sync(priv->idev); | ||
299 | mx25_tcq_re_enable_touch_detection(priv); | ||
300 | } else { | ||
301 | /* | ||
302 | * if only one of both touch measurements are | ||
303 | * below the threshold, still some bouncing | ||
304 | * happens. Take additional samples in this | ||
305 | * case to be sure | ||
306 | */ | ||
307 | mx25_tcq_enable_fifo_irq(priv); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | static irqreturn_t mx25_tcq_irq_thread(int irq, void *dev_id) | ||
313 | { | ||
314 | struct mx25_tcq_priv *priv = dev_id; | ||
315 | u32 sample_buf[TSC_MAX_SAMPLES]; | ||
316 | unsigned int samples; | ||
317 | u32 stats; | ||
318 | unsigned int i; | ||
319 | |||
320 | /* | ||
321 | * Check how many samples are available. We always have to read exactly | ||
322 | * sample_count samples from the fifo, or a multiple of sample_count. | ||
323 | * Otherwise we mixup samples into different touch events. | ||
324 | */ | ||
325 | regmap_read(priv->regs, MX25_ADCQ_SR, &stats); | ||
326 | samples = MX25_ADCQ_SR_FDN(stats); | ||
327 | samples -= samples % priv->sample_count; | ||
328 | |||
329 | if (!samples) | ||
330 | return IRQ_HANDLED; | ||
331 | |||
332 | for (i = 0; i != samples; ++i) | ||
333 | regmap_read(priv->regs, MX25_ADCQ_FIFO, &sample_buf[i]); | ||
334 | |||
335 | mx25_tcq_create_event_for_4wire(priv, sample_buf, samples); | ||
336 | |||
337 | return IRQ_HANDLED; | ||
338 | } | ||
339 | |||
340 | static irqreturn_t mx25_tcq_irq(int irq, void *dev_id) | ||
341 | { | ||
342 | struct mx25_tcq_priv *priv = dev_id; | ||
343 | u32 stat; | ||
344 | int ret = IRQ_HANDLED; | ||
345 | |||
346 | regmap_read(priv->regs, MX25_ADCQ_SR, &stat); | ||
347 | |||
348 | if (stat & (MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR)) | ||
349 | mx25_tcq_re_enable_touch_detection(priv); | ||
350 | |||
351 | if (stat & MX25_ADCQ_SR_PD) { | ||
352 | mx25_tcq_disable_touch_irq(priv); | ||
353 | mx25_tcq_force_queue_start(priv); | ||
354 | mx25_tcq_enable_fifo_irq(priv); | ||
355 | } | ||
356 | |||
357 | if (stat & MX25_ADCQ_SR_FDRY) { | ||
358 | mx25_tcq_disable_fifo_irq(priv); | ||
359 | ret = IRQ_WAKE_THREAD; | ||
360 | } | ||
361 | |||
362 | regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR | | ||
363 | MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR | | ||
364 | MX25_ADCQ_SR_PD, | ||
365 | MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR | | ||
366 | MX25_ADCQ_SR_FOR | MX25_ADCQ_SR_PD); | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | /* configure the state machine for a 4-wire touchscreen */ | ||
372 | static int mx25_tcq_init(struct mx25_tcq_priv *priv) | ||
373 | { | ||
374 | u32 tgcr; | ||
375 | unsigned int ipg_div; | ||
376 | unsigned int adc_period; | ||
377 | unsigned int debounce_cnt; | ||
378 | unsigned int settling_cnt; | ||
379 | int itemct; | ||
380 | int error; | ||
381 | |||
382 | regmap_read(priv->core_regs, MX25_TSC_TGCR, &tgcr); | ||
383 | ipg_div = max_t(unsigned int, 4, MX25_TGCR_GET_ADCCLK(tgcr)); | ||
384 | adc_period = USEC_PER_SEC * ipg_div * 2 + 2; | ||
385 | adc_period /= clk_get_rate(priv->clk) / 1000 + 1; | ||
386 | debounce_cnt = DIV_ROUND_UP(priv->pen_debounce, adc_period * 8) - 1; | ||
387 | settling_cnt = DIV_ROUND_UP(priv->settling_time, adc_period * 8) - 1; | ||
388 | |||
389 | /* Reset */ | ||
390 | regmap_write(priv->regs, MX25_ADCQ_CR, | ||
391 | MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST); | ||
392 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, | ||
393 | MX25_ADCQ_CR_QRST | MX25_ADCQ_CR_FRST, 0); | ||
394 | |||
395 | /* up to 128 * 8 ADC clocks are possible */ | ||
396 | if (debounce_cnt > 127) | ||
397 | debounce_cnt = 127; | ||
398 | |||
399 | /* up to 255 * 8 ADC clocks are possible */ | ||
400 | if (settling_cnt > 255) | ||
401 | settling_cnt = 255; | ||
402 | |||
403 | error = imx25_setup_queue_4wire(priv, settling_cnt, &itemct); | ||
404 | if (error) | ||
405 | return error; | ||
406 | |||
407 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, | ||
408 | MX25_ADCQ_CR_LITEMID_MASK | MX25_ADCQ_CR_WMRK_MASK, | ||
409 | MX25_ADCQ_CR_LITEMID(itemct - 1) | | ||
410 | MX25_ADCQ_CR_WMRK(priv->expected_samples - 1)); | ||
411 | |||
412 | /* setup debounce count */ | ||
413 | regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, | ||
414 | MX25_TGCR_PDBTIME_MASK, | ||
415 | MX25_TGCR_PDBTIME(debounce_cnt)); | ||
416 | |||
417 | /* enable debounce */ | ||
418 | regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDBEN, | ||
419 | MX25_TGCR_PDBEN); | ||
420 | regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDEN, | ||
421 | MX25_TGCR_PDEN); | ||
422 | |||
423 | /* enable the engine on demand */ | ||
424 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QSM_MASK, | ||
425 | MX25_ADCQ_CR_QSM_FQS); | ||
426 | |||
427 | /* Enable repeat and repeat wait */ | ||
428 | regmap_update_bits(priv->regs, MX25_ADCQ_CR, | ||
429 | MX25_ADCQ_CR_RPT | MX25_ADCQ_CR_RWAIT_MASK, | ||
430 | MX25_ADCQ_CR_RPT | | ||
431 | MX25_ADCQ_CR_RWAIT(MX25_TSC_REPEAT_WAIT)); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int mx25_tcq_parse_dt(struct platform_device *pdev, | ||
437 | struct mx25_tcq_priv *priv) | ||
438 | { | ||
439 | struct device_node *np = pdev->dev.of_node; | ||
440 | u32 wires; | ||
441 | int error; | ||
442 | |||
443 | /* Setup defaults */ | ||
444 | priv->pen_threshold = 500; | ||
445 | priv->sample_count = 3; | ||
446 | priv->pen_debounce = 1000000; | ||
447 | priv->settling_time = 250000; | ||
448 | |||
449 | error = of_property_read_u32(np, "fsl,wires", &wires); | ||
450 | if (error) { | ||
451 | dev_err(&pdev->dev, "Failed to find fsl,wires properties\n"); | ||
452 | return error; | ||
453 | } | ||
454 | |||
455 | if (wires == 4) { | ||
456 | priv->mode = MX25_TS_4WIRE; | ||
457 | } else { | ||
458 | dev_err(&pdev->dev, "%u-wire mode not supported\n", wires); | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | /* These are optional, we don't care about the return values */ | ||
463 | of_property_read_u32(np, "fsl,pen-threshold", &priv->pen_threshold); | ||
464 | of_property_read_u32(np, "fsl,settling-time-ns", &priv->settling_time); | ||
465 | of_property_read_u32(np, "fsl,pen-debounce-ns", &priv->pen_debounce); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int mx25_tcq_open(struct input_dev *idev) | ||
471 | { | ||
472 | struct device *dev = &idev->dev; | ||
473 | struct mx25_tcq_priv *priv = dev_get_drvdata(dev); | ||
474 | int error; | ||
475 | |||
476 | error = clk_prepare_enable(priv->clk); | ||
477 | if (error) { | ||
478 | dev_err(dev, "Failed to enable ipg clock\n"); | ||
479 | return error; | ||
480 | } | ||
481 | |||
482 | error = mx25_tcq_init(priv); | ||
483 | if (error) { | ||
484 | dev_err(dev, "Failed to init tcq\n"); | ||
485 | clk_disable_unprepare(priv->clk); | ||
486 | return error; | ||
487 | } | ||
488 | |||
489 | mx25_tcq_re_enable_touch_detection(priv); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static void mx25_tcq_close(struct input_dev *idev) | ||
495 | { | ||
496 | struct mx25_tcq_priv *priv = input_get_drvdata(idev); | ||
497 | |||
498 | mx25_tcq_force_queue_stop(priv); | ||
499 | mx25_tcq_disable_touch_irq(priv); | ||
500 | mx25_tcq_disable_fifo_irq(priv); | ||
501 | clk_disable_unprepare(priv->clk); | ||
502 | } | ||
503 | |||
504 | static int mx25_tcq_probe(struct platform_device *pdev) | ||
505 | { | ||
506 | struct device *dev = &pdev->dev; | ||
507 | struct input_dev *idev; | ||
508 | struct mx25_tcq_priv *priv; | ||
509 | struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent); | ||
510 | struct resource *res; | ||
511 | void __iomem *mem; | ||
512 | int error; | ||
513 | |||
514 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
515 | if (!priv) | ||
516 | return -ENOMEM; | ||
517 | priv->dev = dev; | ||
518 | |||
519 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
520 | mem = devm_ioremap_resource(dev, res); | ||
521 | if (IS_ERR(mem)) | ||
522 | return PTR_ERR(mem); | ||
523 | |||
524 | error = mx25_tcq_parse_dt(pdev, priv); | ||
525 | if (error) | ||
526 | return error; | ||
527 | |||
528 | priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_tcq_regconfig); | ||
529 | if (IS_ERR(priv->regs)) { | ||
530 | dev_err(dev, "Failed to initialize regmap\n"); | ||
531 | return PTR_ERR(priv->regs); | ||
532 | } | ||
533 | |||
534 | priv->irq = platform_get_irq(pdev, 0); | ||
535 | if (priv->irq <= 0) { | ||
536 | dev_err(dev, "Failed to get IRQ\n"); | ||
537 | return priv->irq; | ||
538 | } | ||
539 | |||
540 | idev = devm_input_allocate_device(dev); | ||
541 | if (!idev) { | ||
542 | dev_err(dev, "Failed to allocate input device\n"); | ||
543 | return -ENOMEM; | ||
544 | } | ||
545 | |||
546 | idev->name = mx25_tcq_name; | ||
547 | input_set_capability(idev, EV_KEY, BTN_TOUCH); | ||
548 | input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0); | ||
549 | input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0); | ||
550 | |||
551 | idev->id.bustype = BUS_HOST; | ||
552 | idev->open = mx25_tcq_open; | ||
553 | idev->close = mx25_tcq_close; | ||
554 | |||
555 | priv->idev = idev; | ||
556 | input_set_drvdata(idev, priv); | ||
557 | |||
558 | priv->core_regs = tsadc->regs; | ||
559 | if (!priv->core_regs) | ||
560 | return -EINVAL; | ||
561 | |||
562 | priv->clk = tsadc->clk; | ||
563 | if (!priv->clk) | ||
564 | return -EINVAL; | ||
565 | |||
566 | platform_set_drvdata(pdev, priv); | ||
567 | |||
568 | error = devm_request_threaded_irq(dev, priv->irq, mx25_tcq_irq, | ||
569 | mx25_tcq_irq_thread, 0, pdev->name, | ||
570 | priv); | ||
571 | if (error) { | ||
572 | dev_err(dev, "Failed requesting IRQ\n"); | ||
573 | return error; | ||
574 | } | ||
575 | |||
576 | error = input_register_device(idev); | ||
577 | if (error) { | ||
578 | dev_err(dev, "Failed to register input device\n"); | ||
579 | return error; | ||
580 | } | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static struct platform_driver mx25_tcq_driver = { | ||
586 | .driver = { | ||
587 | .name = "mx25-tcq", | ||
588 | .of_match_table = mx25_tcq_ids, | ||
589 | }, | ||
590 | .probe = mx25_tcq_probe, | ||
591 | }; | ||
592 | module_platform_driver(mx25_tcq_driver); | ||
593 | |||
594 | MODULE_DESCRIPTION("TS input driver for Freescale mx25"); | ||
595 | MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>"); | ||
596 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 515c20a6e10f..73861ad22df4 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c | |||
@@ -848,7 +848,7 @@ static int wdt87xx_do_update_firmware(struct i2c_client *client, | |||
848 | error = wdt87xx_get_sysparam(client, &wdt->param); | 848 | error = wdt87xx_get_sysparam(client, &wdt->param); |
849 | if (error) | 849 | if (error) |
850 | dev_err(&client->dev, | 850 | dev_err(&client->dev, |
851 | "failed to refresh system paramaters: %d\n", error); | 851 | "failed to refresh system parameters: %d\n", error); |
852 | out: | 852 | out: |
853 | enable_irq(client->irq); | 853 | enable_irq(client->irq); |
854 | mutex_unlock(&wdt->fw_mutex); | 854 | mutex_unlock(&wdt->fw_mutex); |