diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input-mt.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 3 | ||||
-rw-r--r-- | drivers/input/keyboard/tca8418_keypad.c | 2 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/arizona-haptics.c | 255 | ||||
-rw-r--r-- | drivers/input/misc/da9052_onkey.c | 22 | ||||
-rw-r--r-- | drivers/input/serio/i8042-x86ia64io.h | 9 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 6 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_tsadcc.c | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/da9052_tsi.c | 59 | ||||
-rw-r--r-- | drivers/input/touchscreen/ti_am335x_tsc.c | 398 | ||||
-rw-r--r-- | drivers/input/touchscreen/ti_tscadc.c | 486 |
14 files changed, 707 insertions, 550 deletions
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c2f436ce7f5b..47a6009dbf43 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c | |||
@@ -251,7 +251,7 @@ void input_mt_sync_frame(struct input_dev *dev) | |||
251 | 251 | ||
252 | if (mt->flags & INPUT_MT_DROP_UNUSED) { | 252 | if (mt->flags & INPUT_MT_DROP_UNUSED) { |
253 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { | 253 | for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { |
254 | if (s->frame == mt->frame) | 254 | if (input_mt_is_used(mt, s)) |
255 | continue; | 255 | continue; |
256 | input_mt_slot(dev, s - mt->slots); | 256 | input_mt_slot(dev, s - mt->slots); |
257 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); | 257 | input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 48309641b1b2..5a240c60342d 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
@@ -409,7 +409,7 @@ config KEYBOARD_NEWTON | |||
409 | 409 | ||
410 | config KEYBOARD_NOMADIK | 410 | config KEYBOARD_NOMADIK |
411 | tristate "ST-Ericsson Nomadik SKE keyboard" | 411 | tristate "ST-Ericsson Nomadik SKE keyboard" |
412 | depends on PLAT_NOMADIK | 412 | depends on (ARCH_NOMADIK || ARCH_U8500) |
413 | select INPUT_MATRIXKMAP | 413 | select INPUT_MATRIXKMAP |
414 | help | 414 | help |
415 | Say Y here if you want to use a keypad provided on the SKE controller | 415 | Say Y here if you want to use a keypad provided on the SKE controller |
@@ -544,6 +544,7 @@ config KEYBOARD_OMAP | |||
544 | 544 | ||
545 | config KEYBOARD_OMAP4 | 545 | config KEYBOARD_OMAP4 |
546 | tristate "TI OMAP4+ keypad support" | 546 | tristate "TI OMAP4+ keypad support" |
547 | depends on ARCH_OMAP2PLUS | ||
547 | select INPUT_MATRIXKMAP | 548 | select INPUT_MATRIXKMAP |
548 | help | 549 | help |
549 | Say Y here if you want to use the OMAP4+ keypad. | 550 | Say Y here if you want to use the OMAP4+ keypad. |
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 50e9c5e195e1..a34cc6714e5b 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c | |||
@@ -384,7 +384,7 @@ static const struct i2c_device_id tca8418_id[] = { | |||
384 | MODULE_DEVICE_TABLE(i2c, tca8418_id); | 384 | MODULE_DEVICE_TABLE(i2c, tca8418_id); |
385 | 385 | ||
386 | #ifdef CONFIG_OF | 386 | #ifdef CONFIG_OF |
387 | static const struct of_device_id tca8418_dt_ids[] __devinitconst = { | 387 | static const struct of_device_id tca8418_dt_ids[] = { |
388 | { .compatible = "ti,tca8418", }, | 388 | { .compatible = "ti,tca8418", }, |
389 | { } | 389 | { } |
390 | }; | 390 | }; |
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 2a1647ef5610..259ef31abb18 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
@@ -72,6 +72,16 @@ config INPUT_AD714X_SPI | |||
72 | To compile this driver as a module, choose M here: the | 72 | To compile this driver as a module, choose M here: the |
73 | module will be called ad714x-spi. | 73 | module will be called ad714x-spi. |
74 | 74 | ||
75 | config INPUT_ARIZONA_HAPTICS | ||
76 | tristate "Arizona haptics support" | ||
77 | depends on MFD_ARIZONA && SND_SOC | ||
78 | select INPUT_FF_MEMLESS | ||
79 | help | ||
80 | Say Y to enable support for the haptics module in Arizona CODECs. | ||
81 | |||
82 | To compile this driver as a module, choose M here: the | ||
83 | module will be called arizona-haptics. | ||
84 | |||
75 | config INPUT_BMA150 | 85 | config INPUT_BMA150 |
76 | tristate "BMA150/SMB380 acceleration sensor support" | 86 | tristate "BMA150/SMB380 acceleration sensor support" |
77 | depends on I2C | 87 | depends on I2C |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 1f874afeea6a..1f1e1b109d9d 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_INPUT_ADXL34X) += adxl34x.o | |||
14 | obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o | 14 | obj-$(CONFIG_INPUT_ADXL34X_I2C) += adxl34x-i2c.o |
15 | obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o | 15 | obj-$(CONFIG_INPUT_ADXL34X_SPI) += adxl34x-spi.o |
16 | obj-$(CONFIG_INPUT_APANEL) += apanel.o | 16 | obj-$(CONFIG_INPUT_APANEL) += apanel.o |
17 | obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o | ||
17 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o | 18 | obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o |
18 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o | 19 | obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o |
19 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o | 20 | obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o |
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c new file mode 100644 index 000000000000..7a04f54ef961 --- /dev/null +++ b/drivers/input/misc/arizona-haptics.c | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * Arizona haptics driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/slab.h> | ||
17 | |||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include <linux/mfd/arizona/core.h> | ||
22 | #include <linux/mfd/arizona/pdata.h> | ||
23 | #include <linux/mfd/arizona/registers.h> | ||
24 | |||
25 | struct arizona_haptics { | ||
26 | struct arizona *arizona; | ||
27 | struct input_dev *input_dev; | ||
28 | struct work_struct work; | ||
29 | |||
30 | struct mutex mutex; | ||
31 | u8 intensity; | ||
32 | }; | ||
33 | |||
34 | static void arizona_haptics_work(struct work_struct *work) | ||
35 | { | ||
36 | struct arizona_haptics *haptics = container_of(work, | ||
37 | struct arizona_haptics, | ||
38 | work); | ||
39 | struct arizona *arizona = haptics->arizona; | ||
40 | struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex; | ||
41 | int ret; | ||
42 | |||
43 | if (!haptics->arizona->dapm) { | ||
44 | dev_err(arizona->dev, "No DAPM context\n"); | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | if (haptics->intensity) { | ||
49 | ret = regmap_update_bits(arizona->regmap, | ||
50 | ARIZONA_HAPTICS_PHASE_2_INTENSITY, | ||
51 | ARIZONA_PHASE2_INTENSITY_MASK, | ||
52 | haptics->intensity); | ||
53 | if (ret != 0) { | ||
54 | dev_err(arizona->dev, "Failed to set intensity: %d\n", | ||
55 | ret); | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | /* This enable sequence will be a noop if already enabled */ | ||
60 | ret = regmap_update_bits(arizona->regmap, | ||
61 | ARIZONA_HAPTICS_CONTROL_1, | ||
62 | ARIZONA_HAP_CTRL_MASK, | ||
63 | 1 << ARIZONA_HAP_CTRL_SHIFT); | ||
64 | if (ret != 0) { | ||
65 | dev_err(arizona->dev, "Failed to start haptics: %d\n", | ||
66 | ret); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
71 | |||
72 | ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS"); | ||
73 | if (ret != 0) { | ||
74 | dev_err(arizona->dev, "Failed to start HAPTICS: %d\n", | ||
75 | ret); | ||
76 | mutex_unlock(dapm_mutex); | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | ret = snd_soc_dapm_sync(arizona->dapm); | ||
81 | if (ret != 0) { | ||
82 | dev_err(arizona->dev, "Failed to sync DAPM: %d\n", | ||
83 | ret); | ||
84 | mutex_unlock(dapm_mutex); | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | mutex_unlock(dapm_mutex); | ||
89 | |||
90 | } else { | ||
91 | /* This disable sequence will be a noop if already enabled */ | ||
92 | mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
93 | |||
94 | ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS"); | ||
95 | if (ret != 0) { | ||
96 | dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n", | ||
97 | ret); | ||
98 | mutex_unlock(dapm_mutex); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | ret = snd_soc_dapm_sync(arizona->dapm); | ||
103 | if (ret != 0) { | ||
104 | dev_err(arizona->dev, "Failed to sync DAPM: %d\n", | ||
105 | ret); | ||
106 | mutex_unlock(dapm_mutex); | ||
107 | return; | ||
108 | } | ||
109 | |||
110 | mutex_unlock(dapm_mutex); | ||
111 | |||
112 | ret = regmap_update_bits(arizona->regmap, | ||
113 | ARIZONA_HAPTICS_CONTROL_1, | ||
114 | ARIZONA_HAP_CTRL_MASK, | ||
115 | 1 << ARIZONA_HAP_CTRL_SHIFT); | ||
116 | if (ret != 0) { | ||
117 | dev_err(arizona->dev, "Failed to stop haptics: %d\n", | ||
118 | ret); | ||
119 | return; | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static int arizona_haptics_play(struct input_dev *input, void *data, | ||
125 | struct ff_effect *effect) | ||
126 | { | ||
127 | struct arizona_haptics *haptics = input_get_drvdata(input); | ||
128 | struct arizona *arizona = haptics->arizona; | ||
129 | |||
130 | if (!arizona->dapm) { | ||
131 | dev_err(arizona->dev, "No DAPM context\n"); | ||
132 | return -EBUSY; | ||
133 | } | ||
134 | |||
135 | if (effect->u.rumble.strong_magnitude) { | ||
136 | /* Scale the magnitude into the range the device supports */ | ||
137 | if (arizona->pdata.hap_act) { | ||
138 | haptics->intensity = | ||
139 | effect->u.rumble.strong_magnitude >> 9; | ||
140 | if (effect->direction < 0x8000) | ||
141 | haptics->intensity += 0x7f; | ||
142 | } else { | ||
143 | haptics->intensity = | ||
144 | effect->u.rumble.strong_magnitude >> 8; | ||
145 | } | ||
146 | } else { | ||
147 | haptics->intensity = 0; | ||
148 | } | ||
149 | |||
150 | schedule_work(&haptics->work); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void arizona_haptics_close(struct input_dev *input) | ||
156 | { | ||
157 | struct arizona_haptics *haptics = input_get_drvdata(input); | ||
158 | struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex; | ||
159 | |||
160 | cancel_work_sync(&haptics->work); | ||
161 | |||
162 | mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
163 | |||
164 | if (haptics->arizona->dapm) | ||
165 | snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS"); | ||
166 | |||
167 | mutex_unlock(dapm_mutex); | ||
168 | } | ||
169 | |||
170 | static int arizona_haptics_probe(struct platform_device *pdev) | ||
171 | { | ||
172 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | ||
173 | struct arizona_haptics *haptics; | ||
174 | int ret; | ||
175 | |||
176 | haptics = devm_kzalloc(&pdev->dev, sizeof(*haptics), GFP_KERNEL); | ||
177 | if (!haptics) | ||
178 | return -ENOMEM; | ||
179 | |||
180 | haptics->arizona = arizona; | ||
181 | |||
182 | ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1, | ||
183 | ARIZONA_HAP_ACT, arizona->pdata.hap_act); | ||
184 | if (ret != 0) { | ||
185 | dev_err(arizona->dev, "Failed to set haptics actuator: %d\n", | ||
186 | ret); | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | INIT_WORK(&haptics->work, arizona_haptics_work); | ||
191 | |||
192 | haptics->input_dev = input_allocate_device(); | ||
193 | if (haptics->input_dev == NULL) { | ||
194 | dev_err(arizona->dev, "Failed to allocate input device\n"); | ||
195 | return -ENOMEM; | ||
196 | } | ||
197 | |||
198 | input_set_drvdata(haptics->input_dev, haptics); | ||
199 | |||
200 | haptics->input_dev->name = "arizona:haptics"; | ||
201 | haptics->input_dev->dev.parent = pdev->dev.parent; | ||
202 | haptics->input_dev->close = arizona_haptics_close; | ||
203 | __set_bit(FF_RUMBLE, haptics->input_dev->ffbit); | ||
204 | |||
205 | ret = input_ff_create_memless(haptics->input_dev, NULL, | ||
206 | arizona_haptics_play); | ||
207 | if (ret < 0) { | ||
208 | dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n", | ||
209 | ret); | ||
210 | goto err_ialloc; | ||
211 | } | ||
212 | |||
213 | ret = input_register_device(haptics->input_dev); | ||
214 | if (ret < 0) { | ||
215 | dev_err(arizona->dev, "couldn't register input device: %d\n", | ||
216 | ret); | ||
217 | goto err_iff; | ||
218 | } | ||
219 | |||
220 | platform_set_drvdata(pdev, haptics); | ||
221 | |||
222 | return 0; | ||
223 | |||
224 | err_iff: | ||
225 | if (haptics->input_dev) | ||
226 | input_ff_destroy(haptics->input_dev); | ||
227 | err_ialloc: | ||
228 | input_free_device(haptics->input_dev); | ||
229 | |||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | static int arizona_haptics_remove(struct platform_device *pdev) | ||
234 | { | ||
235 | struct arizona_haptics *haptics = platform_get_drvdata(pdev); | ||
236 | |||
237 | input_unregister_device(haptics->input_dev); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static struct platform_driver arizona_haptics_driver = { | ||
243 | .probe = arizona_haptics_probe, | ||
244 | .remove = arizona_haptics_remove, | ||
245 | .driver = { | ||
246 | .name = "arizona-haptics", | ||
247 | .owner = THIS_MODULE, | ||
248 | }, | ||
249 | }; | ||
250 | module_platform_driver(arizona_haptics_driver); | ||
251 | |||
252 | MODULE_ALIAS("platform:arizona-haptics"); | ||
253 | MODULE_DESCRIPTION("Arizona haptics driver"); | ||
254 | MODULE_LICENSE("GPL"); | ||
255 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index 630c1ce4980a..020569a499f2 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c | |||
@@ -24,7 +24,6 @@ struct da9052_onkey { | |||
24 | struct da9052 *da9052; | 24 | struct da9052 *da9052; |
25 | struct input_dev *input; | 25 | struct input_dev *input; |
26 | struct delayed_work work; | 26 | struct delayed_work work; |
27 | unsigned int irq; | ||
28 | }; | 27 | }; |
29 | 28 | ||
30 | static void da9052_onkey_query(struct da9052_onkey *onkey) | 29 | static void da9052_onkey_query(struct da9052_onkey *onkey) |
@@ -76,7 +75,6 @@ static int da9052_onkey_probe(struct platform_device *pdev) | |||
76 | struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); | 75 | struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); |
77 | struct da9052_onkey *onkey; | 76 | struct da9052_onkey *onkey; |
78 | struct input_dev *input_dev; | 77 | struct input_dev *input_dev; |
79 | int irq; | ||
80 | int error; | 78 | int error; |
81 | 79 | ||
82 | if (!da9052) { | 80 | if (!da9052) { |
@@ -84,13 +82,6 @@ static int da9052_onkey_probe(struct platform_device *pdev) | |||
84 | return -EINVAL; | 82 | return -EINVAL; |
85 | } | 83 | } |
86 | 84 | ||
87 | irq = platform_get_irq_byname(pdev, "ONKEY"); | ||
88 | if (irq < 0) { | ||
89 | dev_err(&pdev->dev, | ||
90 | "Failed to get an IRQ for input device, %d\n", irq); | ||
91 | return -EINVAL; | ||
92 | } | ||
93 | |||
94 | onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); | 85 | onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); |
95 | input_dev = input_allocate_device(); | 86 | input_dev = input_allocate_device(); |
96 | if (!onkey || !input_dev) { | 87 | if (!onkey || !input_dev) { |
@@ -101,7 +92,6 @@ static int da9052_onkey_probe(struct platform_device *pdev) | |||
101 | 92 | ||
102 | onkey->input = input_dev; | 93 | onkey->input = input_dev; |
103 | onkey->da9052 = da9052; | 94 | onkey->da9052 = da9052; |
104 | onkey->irq = irq; | ||
105 | INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work); | 95 | INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work); |
106 | 96 | ||
107 | input_dev->name = "da9052-onkey"; | 97 | input_dev->name = "da9052-onkey"; |
@@ -111,13 +101,11 @@ static int da9052_onkey_probe(struct platform_device *pdev) | |||
111 | input_dev->evbit[0] = BIT_MASK(EV_KEY); | 101 | input_dev->evbit[0] = BIT_MASK(EV_KEY); |
112 | __set_bit(KEY_POWER, input_dev->keybit); | 102 | __set_bit(KEY_POWER, input_dev->keybit); |
113 | 103 | ||
114 | error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq, | 104 | error = da9052_request_irq(onkey->da9052, DA9052_IRQ_NONKEY, "ONKEY", |
115 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 105 | da9052_onkey_irq, onkey); |
116 | "ONKEY", onkey); | ||
117 | if (error < 0) { | 106 | if (error < 0) { |
118 | dev_err(onkey->da9052->dev, | 107 | dev_err(onkey->da9052->dev, |
119 | "Failed to register ONKEY IRQ %d, error = %d\n", | 108 | "Failed to register ONKEY IRQ: %d\n", error); |
120 | onkey->irq, error); | ||
121 | goto err_free_mem; | 109 | goto err_free_mem; |
122 | } | 110 | } |
123 | 111 | ||
@@ -132,7 +120,7 @@ static int da9052_onkey_probe(struct platform_device *pdev) | |||
132 | return 0; | 120 | return 0; |
133 | 121 | ||
134 | err_free_irq: | 122 | err_free_irq: |
135 | free_irq(onkey->irq, onkey); | 123 | da9052_free_irq(onkey->da9052, DA9052_IRQ_NONKEY, onkey); |
136 | cancel_delayed_work_sync(&onkey->work); | 124 | cancel_delayed_work_sync(&onkey->work); |
137 | err_free_mem: | 125 | err_free_mem: |
138 | input_free_device(input_dev); | 126 | input_free_device(input_dev); |
@@ -145,7 +133,7 @@ static int da9052_onkey_remove(struct platform_device *pdev) | |||
145 | { | 133 | { |
146 | struct da9052_onkey *onkey = platform_get_drvdata(pdev); | 134 | struct da9052_onkey *onkey = platform_get_drvdata(pdev); |
147 | 135 | ||
148 | free_irq(onkey->irq, onkey); | 136 | da9052_free_irq(onkey->da9052, DA9052_IRQ_NONKEY, onkey); |
149 | cancel_delayed_work_sync(&onkey->work); | 137 | cancel_delayed_work_sync(&onkey->work); |
150 | 138 | ||
151 | input_unregister_device(onkey->input); | 139 | input_unregister_device(onkey->input); |
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index d6cc77a53c7e..5f306f79da0c 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h | |||
@@ -921,6 +921,7 @@ static int __init i8042_platform_init(void) | |||
921 | int retval; | 921 | int retval; |
922 | 922 | ||
923 | #ifdef CONFIG_X86 | 923 | #ifdef CONFIG_X86 |
924 | u8 a20_on = 0xdf; | ||
924 | /* Just return if pre-detection shows no i8042 controller exist */ | 925 | /* Just return if pre-detection shows no i8042 controller exist */ |
925 | if (!x86_platform.i8042_detect()) | 926 | if (!x86_platform.i8042_detect()) |
926 | return -ENODEV; | 927 | return -ENODEV; |
@@ -960,6 +961,14 @@ static int __init i8042_platform_init(void) | |||
960 | 961 | ||
961 | if (dmi_check_system(i8042_dmi_dritek_table)) | 962 | if (dmi_check_system(i8042_dmi_dritek_table)) |
962 | i8042_dritek = true; | 963 | i8042_dritek = true; |
964 | |||
965 | /* | ||
966 | * A20 was already enabled during early kernel init. But some buggy | ||
967 | * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to | ||
968 | * resume from S3. So we do it here and hope that nothing breaks. | ||
969 | */ | ||
970 | i8042_command(&a20_on, 0x10d1); | ||
971 | i8042_command(NULL, 0x00ff); /* Null command for SMM firmware */ | ||
963 | #endif /* CONFIG_X86 */ | 972 | #endif /* CONFIG_X86 */ |
964 | 973 | ||
965 | return retval; | 974 | return retval; |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b93b5988ace8..515cfe790543 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -517,9 +517,9 @@ config TOUCHSCREEN_TOUCHWIN | |||
517 | To compile this driver as a module, choose M here: the | 517 | To compile this driver as a module, choose M here: the |
518 | module will be called touchwin. | 518 | module will be called touchwin. |
519 | 519 | ||
520 | config TOUCHSCREEN_TI_TSCADC | 520 | config TOUCHSCREEN_TI_AM335X_TSC |
521 | tristate "TI Touchscreen Interface" | 521 | tristate "TI Touchscreen Interface" |
522 | depends on ARCH_OMAP2PLUS | 522 | depends on MFD_TI_AM335X_TSCADC |
523 | help | 523 | help |
524 | Say Y here if you have 4/5/8 wire touchscreen controller | 524 | Say Y here if you have 4/5/8 wire touchscreen controller |
525 | to be connected to the ADC controller on your TI AM335x SoC. | 525 | to be connected to the ADC controller on your TI AM335x SoC. |
@@ -527,7 +527,7 @@ config TOUCHSCREEN_TI_TSCADC | |||
527 | If unsure, say N. | 527 | If unsure, say N. |
528 | 528 | ||
529 | To compile this driver as a module, choose M here: the | 529 | To compile this driver as a module, choose M here: the |
530 | module will be called ti_tscadc. | 530 | module will be called ti_am335x_tsc. |
531 | 531 | ||
532 | config TOUCHSCREEN_ATMEL_TSADCC | 532 | config TOUCHSCREEN_ATMEL_TSADCC |
533 | tristate "Atmel Touchscreen Interface" | 533 | tristate "Atmel Touchscreen Interface" |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5f949c0bf82f..6bfbeab67c9f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -51,7 +51,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | |||
51 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 51 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
52 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 52 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
53 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 53 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
54 | obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o | 54 | obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o |
55 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o | 55 | obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o |
56 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o | 56 | obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o |
57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 57 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c index 55092d1c5cb9..95f6785a94b0 100644 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ b/drivers/input/touchscreen/atmel_tsadcc.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/clk.h> | 22 | #include <linux/clk.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/io.h> | 24 | #include <linux/io.h> |
25 | #include <mach/board.h> | 25 | #include <linux/platform_data/atmel.h> |
26 | #include <mach/cpu.h> | 26 | #include <mach/cpu.h> |
27 | 27 | ||
28 | /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ | 28 | /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ |
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index 303966ffe1e8..8f561e22bdd4 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c | |||
@@ -27,8 +27,6 @@ struct da9052_tsi { | |||
27 | struct input_dev *dev; | 27 | struct input_dev *dev; |
28 | struct delayed_work ts_pen_work; | 28 | struct delayed_work ts_pen_work; |
29 | struct mutex mutex; | 29 | struct mutex mutex; |
30 | unsigned int irq_pendwn; | ||
31 | unsigned int irq_datardy; | ||
32 | bool stopped; | 30 | bool stopped; |
33 | bool adc_on; | 31 | bool adc_on; |
34 | }; | 32 | }; |
@@ -45,8 +43,8 @@ static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data) | |||
45 | 43 | ||
46 | if (!tsi->stopped) { | 44 | if (!tsi->stopped) { |
47 | /* Mask PEN_DOWN event and unmask TSI_READY event */ | 45 | /* Mask PEN_DOWN event and unmask TSI_READY event */ |
48 | disable_irq_nosync(tsi->irq_pendwn); | 46 | da9052_disable_irq_nosync(tsi->da9052, DA9052_IRQ_PENDOWN); |
49 | enable_irq(tsi->irq_datardy); | 47 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
50 | 48 | ||
51 | da9052_ts_adc_toggle(tsi, true); | 49 | da9052_ts_adc_toggle(tsi, true); |
52 | 50 | ||
@@ -137,8 +135,8 @@ static void da9052_ts_pen_work(struct work_struct *work) | |||
137 | return; | 135 | return; |
138 | 136 | ||
139 | /* Mask TSI_READY event and unmask PEN_DOWN event */ | 137 | /* Mask TSI_READY event and unmask PEN_DOWN event */ |
140 | disable_irq(tsi->irq_datardy); | 138 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
141 | enable_irq(tsi->irq_pendwn); | 139 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
142 | } | 140 | } |
143 | } | 141 | } |
144 | } | 142 | } |
@@ -197,7 +195,7 @@ static int da9052_ts_input_open(struct input_dev *input_dev) | |||
197 | mb(); | 195 | mb(); |
198 | 196 | ||
199 | /* Unmask PEN_DOWN event */ | 197 | /* Unmask PEN_DOWN event */ |
200 | enable_irq(tsi->irq_pendwn); | 198 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
201 | 199 | ||
202 | /* Enable Pen Detect Circuit */ | 200 | /* Enable Pen Detect Circuit */ |
203 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, | 201 | return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, |
@@ -210,11 +208,11 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
210 | 208 | ||
211 | tsi->stopped = true; | 209 | tsi->stopped = true; |
212 | mb(); | 210 | mb(); |
213 | disable_irq(tsi->irq_pendwn); | 211 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
214 | cancel_delayed_work_sync(&tsi->ts_pen_work); | 212 | cancel_delayed_work_sync(&tsi->ts_pen_work); |
215 | 213 | ||
216 | if (tsi->adc_on) { | 214 | if (tsi->adc_on) { |
217 | disable_irq(tsi->irq_datardy); | 215 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
218 | da9052_ts_adc_toggle(tsi, false); | 216 | da9052_ts_adc_toggle(tsi, false); |
219 | 217 | ||
220 | /* | 218 | /* |
@@ -222,7 +220,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev) | |||
222 | * twice and we need to enable it to keep enable/disable | 220 | * twice and we need to enable it to keep enable/disable |
223 | * counter balanced. IRQ is still off though. | 221 | * counter balanced. IRQ is still off though. |
224 | */ | 222 | */ |
225 | enable_irq(tsi->irq_pendwn); | 223 | da9052_enable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
226 | } | 224 | } |
227 | 225 | ||
228 | /* Disable Pen Detect Circuit */ | 226 | /* Disable Pen Detect Circuit */ |
@@ -234,21 +232,12 @@ static int da9052_ts_probe(struct platform_device *pdev) | |||
234 | struct da9052 *da9052; | 232 | struct da9052 *da9052; |
235 | struct da9052_tsi *tsi; | 233 | struct da9052_tsi *tsi; |
236 | struct input_dev *input_dev; | 234 | struct input_dev *input_dev; |
237 | int irq_pendwn; | ||
238 | int irq_datardy; | ||
239 | int error; | 235 | int error; |
240 | 236 | ||
241 | da9052 = dev_get_drvdata(pdev->dev.parent); | 237 | da9052 = dev_get_drvdata(pdev->dev.parent); |
242 | if (!da9052) | 238 | if (!da9052) |
243 | return -EINVAL; | 239 | return -EINVAL; |
244 | 240 | ||
245 | irq_pendwn = platform_get_irq_byname(pdev, "PENDWN"); | ||
246 | irq_datardy = platform_get_irq_byname(pdev, "TSIRDY"); | ||
247 | if (irq_pendwn < 0 || irq_datardy < 0) { | ||
248 | dev_err(da9052->dev, "Unable to determine device interrupts\n"); | ||
249 | return -ENXIO; | ||
250 | } | ||
251 | |||
252 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); | 241 | tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL); |
253 | input_dev = input_allocate_device(); | 242 | input_dev = input_allocate_device(); |
254 | if (!tsi || !input_dev) { | 243 | if (!tsi || !input_dev) { |
@@ -258,8 +247,6 @@ static int da9052_ts_probe(struct platform_device *pdev) | |||
258 | 247 | ||
259 | tsi->da9052 = da9052; | 248 | tsi->da9052 = da9052; |
260 | tsi->dev = input_dev; | 249 | tsi->dev = input_dev; |
261 | tsi->irq_pendwn = da9052->irq_base + irq_pendwn; | ||
262 | tsi->irq_datardy = da9052->irq_base + irq_datardy; | ||
263 | tsi->stopped = true; | 250 | tsi->stopped = true; |
264 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); | 251 | INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work); |
265 | 252 | ||
@@ -287,31 +274,25 @@ static int da9052_ts_probe(struct platform_device *pdev) | |||
287 | /* Disable ADC */ | 274 | /* Disable ADC */ |
288 | da9052_ts_adc_toggle(tsi, false); | 275 | da9052_ts_adc_toggle(tsi, false); |
289 | 276 | ||
290 | error = request_threaded_irq(tsi->irq_pendwn, | 277 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_PENDOWN, |
291 | NULL, da9052_ts_pendwn_irq, | 278 | "pendown-irq", da9052_ts_pendwn_irq, tsi); |
292 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
293 | "PENDWN", tsi); | ||
294 | if (error) { | 279 | if (error) { |
295 | dev_err(tsi->da9052->dev, | 280 | dev_err(tsi->da9052->dev, |
296 | "Failed to register PENDWN IRQ %d, error = %d\n", | 281 | "Failed to register PENDWN IRQ: %d\n", error); |
297 | tsi->irq_pendwn, error); | ||
298 | goto err_free_mem; | 282 | goto err_free_mem; |
299 | } | 283 | } |
300 | 284 | ||
301 | error = request_threaded_irq(tsi->irq_datardy, | 285 | error = da9052_request_irq(tsi->da9052, DA9052_IRQ_TSIREADY, |
302 | NULL, da9052_ts_datardy_irq, | 286 | "tsiready-irq", da9052_ts_datardy_irq, tsi); |
303 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
304 | "TSIRDY", tsi); | ||
305 | if (error) { | 287 | if (error) { |
306 | dev_err(tsi->da9052->dev, | 288 | dev_err(tsi->da9052->dev, |
307 | "Failed to register TSIRDY IRQ %d, error = %d\n", | 289 | "Failed to register TSIRDY IRQ :%d\n", error); |
308 | tsi->irq_datardy, error); | ||
309 | goto err_free_pendwn_irq; | 290 | goto err_free_pendwn_irq; |
310 | } | 291 | } |
311 | 292 | ||
312 | /* Mask PEN_DOWN and TSI_READY events */ | 293 | /* Mask PEN_DOWN and TSI_READY events */ |
313 | disable_irq(tsi->irq_pendwn); | 294 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_PENDOWN); |
314 | disable_irq(tsi->irq_datardy); | 295 | da9052_disable_irq(tsi->da9052, DA9052_IRQ_TSIREADY); |
315 | 296 | ||
316 | error = da9052_configure_tsi(tsi); | 297 | error = da9052_configure_tsi(tsi); |
317 | if (error) | 298 | if (error) |
@@ -326,9 +307,9 @@ static int da9052_ts_probe(struct platform_device *pdev) | |||
326 | return 0; | 307 | return 0; |
327 | 308 | ||
328 | err_free_datardy_irq: | 309 | err_free_datardy_irq: |
329 | free_irq(tsi->irq_datardy, tsi); | 310 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
330 | err_free_pendwn_irq: | 311 | err_free_pendwn_irq: |
331 | free_irq(tsi->irq_pendwn, tsi); | 312 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
332 | err_free_mem: | 313 | err_free_mem: |
333 | kfree(tsi); | 314 | kfree(tsi); |
334 | input_free_device(input_dev); | 315 | input_free_device(input_dev); |
@@ -342,8 +323,8 @@ static int da9052_ts_remove(struct platform_device *pdev) | |||
342 | 323 | ||
343 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); | 324 | da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19); |
344 | 325 | ||
345 | free_irq(tsi->irq_pendwn, tsi); | 326 | da9052_free_irq(tsi->da9052, DA9052_IRQ_TSIREADY, tsi); |
346 | free_irq(tsi->irq_datardy, tsi); | 327 | da9052_free_irq(tsi->da9052, DA9052_IRQ_PENDOWN, tsi); |
347 | 328 | ||
348 | input_unregister_device(tsi->dev); | 329 | input_unregister_device(tsi->dev); |
349 | kfree(tsi); | 330 | kfree(tsi); |
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c new file mode 100644 index 000000000000..51e7b87827a4 --- /dev/null +++ b/drivers/input/touchscreen/ti_am335x_tsc.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_am335x_tsc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <linux/mfd/ti_am335x_tscadc.h> | ||
31 | |||
32 | #define ADCFSM_STEPID 0x10 | ||
33 | #define SEQ_SETTLE 275 | ||
34 | #define MAX_12BIT ((1 << 12) - 1) | ||
35 | |||
36 | struct titsc { | ||
37 | struct input_dev *input; | ||
38 | struct ti_tscadc_dev *mfd_tscadc; | ||
39 | unsigned int irq; | ||
40 | unsigned int wires; | ||
41 | unsigned int x_plate_resistance; | ||
42 | bool pen_down; | ||
43 | int steps_to_configure; | ||
44 | }; | ||
45 | |||
46 | static unsigned int titsc_readl(struct titsc *ts, unsigned int reg) | ||
47 | { | ||
48 | return readl(ts->mfd_tscadc->tscadc_base + reg); | ||
49 | } | ||
50 | |||
51 | static void titsc_writel(struct titsc *tsc, unsigned int reg, | ||
52 | unsigned int val) | ||
53 | { | ||
54 | writel(val, tsc->mfd_tscadc->tscadc_base + reg); | ||
55 | } | ||
56 | |||
57 | static void titsc_step_config(struct titsc *ts_dev) | ||
58 | { | ||
59 | unsigned int config; | ||
60 | int i, total_steps; | ||
61 | |||
62 | /* Configure the Step registers */ | ||
63 | total_steps = 2 * ts_dev->steps_to_configure; | ||
64 | |||
65 | config = STEPCONFIG_MODE_HWSYNC | | ||
66 | STEPCONFIG_AVG_16 | STEPCONFIG_XPP; | ||
67 | switch (ts_dev->wires) { | ||
68 | case 4: | ||
69 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
70 | break; | ||
71 | case 5: | ||
72 | config |= STEPCONFIG_YNN | | ||
73 | STEPCONFIG_INP_AN4 | STEPCONFIG_XNN | | ||
74 | STEPCONFIG_YPP; | ||
75 | break; | ||
76 | case 8: | ||
77 | config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN; | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | for (i = 1; i <= ts_dev->steps_to_configure; i++) { | ||
82 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
83 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
84 | } | ||
85 | |||
86 | config = 0; | ||
87 | config = STEPCONFIG_MODE_HWSYNC | | ||
88 | STEPCONFIG_AVG_16 | STEPCONFIG_YNN | | ||
89 | STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1; | ||
90 | switch (ts_dev->wires) { | ||
91 | case 4: | ||
92 | config |= STEPCONFIG_YPP; | ||
93 | break; | ||
94 | case 5: | ||
95 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 | | ||
96 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
97 | break; | ||
98 | case 8: | ||
99 | config |= STEPCONFIG_YPP; | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) { | ||
104 | titsc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
105 | titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
106 | } | ||
107 | |||
108 | config = 0; | ||
109 | /* Charge step configuration */ | ||
110 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
111 | STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR | | ||
112 | STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1; | ||
113 | |||
114 | titsc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
115 | titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY); | ||
116 | |||
117 | config = 0; | ||
118 | /* Configure to calculate pressure */ | ||
119 | config = STEPCONFIG_MODE_HWSYNC | | ||
120 | STEPCONFIG_AVG_16 | STEPCONFIG_YPP | | ||
121 | STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM; | ||
122 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config); | ||
123 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1), | ||
124 | STEPCONFIG_OPENDLY); | ||
125 | |||
126 | config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1; | ||
127 | titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config); | ||
128 | titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2), | ||
129 | STEPCONFIG_OPENDLY); | ||
130 | |||
131 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
132 | } | ||
133 | |||
134 | static void titsc_read_coordinates(struct titsc *ts_dev, | ||
135 | unsigned int *x, unsigned int *y) | ||
136 | { | ||
137 | unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
138 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
139 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
140 | unsigned int read, diff; | ||
141 | unsigned int i, channel; | ||
142 | |||
143 | /* | ||
144 | * Delta filter is used to remove large variations in sampled | ||
145 | * values from ADC. The filter tries to predict where the next | ||
146 | * coordinate could be. This is done by taking a previous | ||
147 | * coordinate and subtracting it form current one. Further the | ||
148 | * algorithm compares the difference with that of a present value, | ||
149 | * if true the value is reported to the sub system. | ||
150 | */ | ||
151 | for (i = 0; i < fifocount - 1; i++) { | ||
152 | read = titsc_readl(ts_dev, REG_FIFO0); | ||
153 | channel = read & 0xf0000; | ||
154 | channel = channel >> 0x10; | ||
155 | if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) { | ||
156 | read &= 0xfff; | ||
157 | diff = abs(read - prev_val_x); | ||
158 | if (diff < prev_diff_x) { | ||
159 | prev_diff_x = diff; | ||
160 | *x = read; | ||
161 | } | ||
162 | prev_val_x = read; | ||
163 | } | ||
164 | |||
165 | read = titsc_readl(ts_dev, REG_FIFO1); | ||
166 | channel = read & 0xf0000; | ||
167 | channel = channel >> 0x10; | ||
168 | if ((channel >= ts_dev->steps_to_configure) && | ||
169 | (channel < (2 * ts_dev->steps_to_configure - 1))) { | ||
170 | read &= 0xfff; | ||
171 | diff = abs(read - prev_val_y); | ||
172 | if (diff < prev_diff_y) { | ||
173 | prev_diff_y = diff; | ||
174 | *y = read; | ||
175 | } | ||
176 | prev_val_y = read; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static irqreturn_t titsc_irq(int irq, void *dev) | ||
182 | { | ||
183 | struct titsc *ts_dev = dev; | ||
184 | struct input_dev *input_dev = ts_dev->input; | ||
185 | unsigned int status, irqclr = 0; | ||
186 | unsigned int x = 0, y = 0; | ||
187 | unsigned int z1, z2, z; | ||
188 | unsigned int fsm; | ||
189 | unsigned int fifo1count, fifo0count; | ||
190 | int i; | ||
191 | |||
192 | status = titsc_readl(ts_dev, REG_IRQSTATUS); | ||
193 | if (status & IRQENB_FIFO0THRES) { | ||
194 | titsc_read_coordinates(ts_dev, &x, &y); | ||
195 | |||
196 | z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
197 | z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
198 | |||
199 | fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT); | ||
200 | for (i = 0; i < fifo1count; i++) | ||
201 | titsc_readl(ts_dev, REG_FIFO1); | ||
202 | |||
203 | fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT); | ||
204 | for (i = 0; i < fifo0count; i++) | ||
205 | titsc_readl(ts_dev, REG_FIFO0); | ||
206 | |||
207 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
208 | /* | ||
209 | * Calculate pressure using formula | ||
210 | * Resistance(touch) = x plate resistance * | ||
211 | * x postion/4096 * ((z2 / z1) - 1) | ||
212 | */ | ||
213 | z = z2 - z1; | ||
214 | z *= x; | ||
215 | z *= ts_dev->x_plate_resistance; | ||
216 | z /= z1; | ||
217 | z = (z + 2047) >> 12; | ||
218 | |||
219 | if (z <= MAX_12BIT) { | ||
220 | input_report_abs(input_dev, ABS_X, x); | ||
221 | input_report_abs(input_dev, ABS_Y, y); | ||
222 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
223 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
224 | input_sync(input_dev); | ||
225 | } | ||
226 | } | ||
227 | irqclr |= IRQENB_FIFO0THRES; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Time for sequencer to settle, to read | ||
232 | * correct state of the sequencer. | ||
233 | */ | ||
234 | udelay(SEQ_SETTLE); | ||
235 | |||
236 | status = titsc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
237 | if (status & IRQENB_PENUP) { | ||
238 | /* Pen up event */ | ||
239 | fsm = titsc_readl(ts_dev, REG_ADCFSM); | ||
240 | if (fsm == ADCFSM_STEPID) { | ||
241 | ts_dev->pen_down = false; | ||
242 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
243 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
244 | input_sync(input_dev); | ||
245 | } else { | ||
246 | ts_dev->pen_down = true; | ||
247 | } | ||
248 | irqclr |= IRQENB_PENUP; | ||
249 | } | ||
250 | |||
251 | titsc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
252 | |||
253 | titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC); | ||
254 | return IRQ_HANDLED; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * The functions for inserting/removing driver as a module. | ||
259 | */ | ||
260 | |||
261 | static int titsc_probe(struct platform_device *pdev) | ||
262 | { | ||
263 | struct titsc *ts_dev; | ||
264 | struct input_dev *input_dev; | ||
265 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
266 | struct mfd_tscadc_board *pdata; | ||
267 | int err; | ||
268 | |||
269 | pdata = tscadc_dev->dev->platform_data; | ||
270 | |||
271 | if (!pdata) { | ||
272 | dev_err(&pdev->dev, "Could not find platform data\n"); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | /* Allocate memory for device */ | ||
277 | ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL); | ||
278 | input_dev = input_allocate_device(); | ||
279 | if (!ts_dev || !input_dev) { | ||
280 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
281 | err = -ENOMEM; | ||
282 | goto err_free_mem; | ||
283 | } | ||
284 | |||
285 | tscadc_dev->tsc = ts_dev; | ||
286 | ts_dev->mfd_tscadc = tscadc_dev; | ||
287 | ts_dev->input = input_dev; | ||
288 | ts_dev->irq = tscadc_dev->irq; | ||
289 | ts_dev->wires = pdata->tsc_init->wires; | ||
290 | ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance; | ||
291 | ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure; | ||
292 | |||
293 | err = request_irq(ts_dev->irq, titsc_irq, | ||
294 | 0, pdev->dev.driver->name, ts_dev); | ||
295 | if (err) { | ||
296 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
297 | goto err_free_mem; | ||
298 | } | ||
299 | |||
300 | titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES); | ||
301 | titsc_step_config(ts_dev); | ||
302 | titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure); | ||
303 | |||
304 | input_dev->name = "ti-tsc"; | ||
305 | input_dev->dev.parent = &pdev->dev; | ||
306 | |||
307 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
308 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
309 | |||
310 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
311 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
312 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
313 | |||
314 | /* register to the input system */ | ||
315 | err = input_register_device(input_dev); | ||
316 | if (err) | ||
317 | goto err_free_irq; | ||
318 | |||
319 | platform_set_drvdata(pdev, ts_dev); | ||
320 | return 0; | ||
321 | |||
322 | err_free_irq: | ||
323 | free_irq(ts_dev->irq, ts_dev); | ||
324 | err_free_mem: | ||
325 | input_free_device(input_dev); | ||
326 | kfree(ts_dev); | ||
327 | return err; | ||
328 | } | ||
329 | |||
330 | static int titsc_remove(struct platform_device *pdev) | ||
331 | { | ||
332 | struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data; | ||
333 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
334 | |||
335 | free_irq(ts_dev->irq, ts_dev); | ||
336 | |||
337 | input_unregister_device(ts_dev->input); | ||
338 | |||
339 | platform_set_drvdata(pdev, NULL); | ||
340 | kfree(ts_dev); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | #ifdef CONFIG_PM | ||
345 | static int titsc_suspend(struct device *dev) | ||
346 | { | ||
347 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
348 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
349 | unsigned int idle; | ||
350 | |||
351 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
352 | idle = titsc_readl(ts_dev, REG_IRQENABLE); | ||
353 | titsc_writel(ts_dev, REG_IRQENABLE, | ||
354 | (idle | IRQENB_HW_PEN)); | ||
355 | titsc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
356 | } | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int titsc_resume(struct device *dev) | ||
361 | { | ||
362 | struct ti_tscadc_dev *tscadc_dev = dev->platform_data; | ||
363 | struct titsc *ts_dev = tscadc_dev->tsc; | ||
364 | |||
365 | if (device_may_wakeup(tscadc_dev->dev)) { | ||
366 | titsc_writel(ts_dev, REG_IRQWAKEUP, | ||
367 | 0x00); | ||
368 | titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN); | ||
369 | } | ||
370 | titsc_step_config(ts_dev); | ||
371 | titsc_writel(ts_dev, REG_FIFO0THR, | ||
372 | ts_dev->steps_to_configure); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static const struct dev_pm_ops titsc_pm_ops = { | ||
377 | .suspend = titsc_suspend, | ||
378 | .resume = titsc_resume, | ||
379 | }; | ||
380 | #define TITSC_PM_OPS (&titsc_pm_ops) | ||
381 | #else | ||
382 | #define TITSC_PM_OPS NULL | ||
383 | #endif | ||
384 | |||
385 | static struct platform_driver ti_tsc_driver = { | ||
386 | .probe = titsc_probe, | ||
387 | .remove = titsc_remove, | ||
388 | .driver = { | ||
389 | .name = "tsc", | ||
390 | .owner = THIS_MODULE, | ||
391 | .pm = TITSC_PM_OPS, | ||
392 | }, | ||
393 | }; | ||
394 | module_platform_driver(ti_tsc_driver); | ||
395 | |||
396 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
397 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
398 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/ti_tscadc.c b/drivers/input/touchscreen/ti_tscadc.c deleted file mode 100644 index bcedf2e7468c..000000000000 --- a/drivers/input/touchscreen/ti_tscadc.c +++ /dev/null | |||
@@ -1,486 +0,0 @@ | |||
1 | /* | ||
2 | * TI Touch Screen driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation version 2. | ||
9 | * | ||
10 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
11 | * kind, whether express or implied; without even the implied warranty | ||
12 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/input/ti_tscadc.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #define REG_IRQEOI 0x020 | ||
31 | #define REG_RAWIRQSTATUS 0x024 | ||
32 | #define REG_IRQSTATUS 0x028 | ||
33 | #define REG_IRQENABLE 0x02C | ||
34 | #define REG_IRQWAKEUP 0x034 | ||
35 | #define REG_CTRL 0x040 | ||
36 | #define REG_ADCFSM 0x044 | ||
37 | #define REG_CLKDIV 0x04C | ||
38 | #define REG_SE 0x054 | ||
39 | #define REG_IDLECONFIG 0x058 | ||
40 | #define REG_CHARGECONFIG 0x05C | ||
41 | #define REG_CHARGEDELAY 0x060 | ||
42 | #define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8)) | ||
43 | #define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8)) | ||
44 | #define REG_STEPCONFIG13 0x0C4 | ||
45 | #define REG_STEPDELAY13 0x0C8 | ||
46 | #define REG_STEPCONFIG14 0x0CC | ||
47 | #define REG_STEPDELAY14 0x0D0 | ||
48 | #define REG_FIFO0CNT 0xE4 | ||
49 | #define REG_FIFO1THR 0xF4 | ||
50 | #define REG_FIFO0 0x100 | ||
51 | #define REG_FIFO1 0x200 | ||
52 | |||
53 | /* Register Bitfields */ | ||
54 | #define IRQWKUP_ENB BIT(0) | ||
55 | #define STPENB_STEPENB 0x7FFF | ||
56 | #define IRQENB_FIFO1THRES BIT(5) | ||
57 | #define IRQENB_PENUP BIT(9) | ||
58 | #define STEPCONFIG_MODE_HWSYNC 0x2 | ||
59 | #define STEPCONFIG_SAMPLES_AVG (1 << 4) | ||
60 | #define STEPCONFIG_XPP (1 << 5) | ||
61 | #define STEPCONFIG_XNN (1 << 6) | ||
62 | #define STEPCONFIG_YPP (1 << 7) | ||
63 | #define STEPCONFIG_YNN (1 << 8) | ||
64 | #define STEPCONFIG_XNP (1 << 9) | ||
65 | #define STEPCONFIG_YPN (1 << 10) | ||
66 | #define STEPCONFIG_INM (1 << 18) | ||
67 | #define STEPCONFIG_INP (1 << 20) | ||
68 | #define STEPCONFIG_INP_5 (1 << 21) | ||
69 | #define STEPCONFIG_FIFO1 (1 << 26) | ||
70 | #define STEPCONFIG_OPENDLY 0xff | ||
71 | #define STEPCONFIG_Z1 (3 << 19) | ||
72 | #define STEPIDLE_INP (1 << 22) | ||
73 | #define STEPCHARGE_RFP (1 << 12) | ||
74 | #define STEPCHARGE_INM (1 << 15) | ||
75 | #define STEPCHARGE_INP (1 << 19) | ||
76 | #define STEPCHARGE_RFM (1 << 23) | ||
77 | #define STEPCHARGE_DELAY 0x1 | ||
78 | #define CNTRLREG_TSCSSENB (1 << 0) | ||
79 | #define CNTRLREG_STEPID (1 << 1) | ||
80 | #define CNTRLREG_STEPCONFIGWRT (1 << 2) | ||
81 | #define CNTRLREG_4WIRE (1 << 5) | ||
82 | #define CNTRLREG_5WIRE (1 << 6) | ||
83 | #define CNTRLREG_8WIRE (3 << 5) | ||
84 | #define CNTRLREG_TSCENB (1 << 7) | ||
85 | #define ADCFSM_STEPID 0x10 | ||
86 | |||
87 | #define SEQ_SETTLE 275 | ||
88 | #define ADC_CLK 3000000 | ||
89 | #define MAX_12BIT ((1 << 12) - 1) | ||
90 | #define TSCADC_DELTA_X 15 | ||
91 | #define TSCADC_DELTA_Y 15 | ||
92 | |||
93 | struct tscadc { | ||
94 | struct input_dev *input; | ||
95 | struct clk *tsc_ick; | ||
96 | void __iomem *tsc_base; | ||
97 | unsigned int irq; | ||
98 | unsigned int wires; | ||
99 | unsigned int x_plate_resistance; | ||
100 | bool pen_down; | ||
101 | }; | ||
102 | |||
103 | static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg) | ||
104 | { | ||
105 | return readl(ts->tsc_base + reg); | ||
106 | } | ||
107 | |||
108 | static void tscadc_writel(struct tscadc *tsc, unsigned int reg, | ||
109 | unsigned int val) | ||
110 | { | ||
111 | writel(val, tsc->tsc_base + reg); | ||
112 | } | ||
113 | |||
114 | static void tscadc_step_config(struct tscadc *ts_dev) | ||
115 | { | ||
116 | unsigned int config; | ||
117 | int i; | ||
118 | |||
119 | /* Configure the Step registers */ | ||
120 | |||
121 | config = STEPCONFIG_MODE_HWSYNC | | ||
122 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP; | ||
123 | switch (ts_dev->wires) { | ||
124 | case 4: | ||
125 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
126 | break; | ||
127 | case 5: | ||
128 | config |= STEPCONFIG_YNN | | ||
129 | STEPCONFIG_INP_5 | STEPCONFIG_XNN | | ||
130 | STEPCONFIG_YPP; | ||
131 | break; | ||
132 | case 8: | ||
133 | config |= STEPCONFIG_INP | STEPCONFIG_XNN; | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | for (i = 1; i < 7; i++) { | ||
138 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
139 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
140 | } | ||
141 | |||
142 | config = 0; | ||
143 | config = STEPCONFIG_MODE_HWSYNC | | ||
144 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN | | ||
145 | STEPCONFIG_INM | STEPCONFIG_FIFO1; | ||
146 | switch (ts_dev->wires) { | ||
147 | case 4: | ||
148 | config |= STEPCONFIG_YPP; | ||
149 | break; | ||
150 | case 5: | ||
151 | config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 | | ||
152 | STEPCONFIG_XNP | STEPCONFIG_YPN; | ||
153 | break; | ||
154 | case 8: | ||
155 | config |= STEPCONFIG_YPP; | ||
156 | break; | ||
157 | } | ||
158 | |||
159 | for (i = 7; i < 13; i++) { | ||
160 | tscadc_writel(ts_dev, REG_STEPCONFIG(i), config); | ||
161 | tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); | ||
162 | } | ||
163 | |||
164 | config = 0; | ||
165 | /* Charge step configuration */ | ||
166 | config = STEPCONFIG_XPP | STEPCONFIG_YNN | | ||
167 | STEPCHARGE_RFP | STEPCHARGE_RFM | | ||
168 | STEPCHARGE_INM | STEPCHARGE_INP; | ||
169 | |||
170 | tscadc_writel(ts_dev, REG_CHARGECONFIG, config); | ||
171 | tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY); | ||
172 | |||
173 | config = 0; | ||
174 | /* Configure to calculate pressure */ | ||
175 | config = STEPCONFIG_MODE_HWSYNC | | ||
176 | STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP | | ||
177 | STEPCONFIG_XNN | STEPCONFIG_INM; | ||
178 | tscadc_writel(ts_dev, REG_STEPCONFIG13, config); | ||
179 | tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY); | ||
180 | |||
181 | config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1; | ||
182 | tscadc_writel(ts_dev, REG_STEPCONFIG14, config); | ||
183 | tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY); | ||
184 | |||
185 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
186 | } | ||
187 | |||
188 | static void tscadc_idle_config(struct tscadc *ts_config) | ||
189 | { | ||
190 | unsigned int idleconfig; | ||
191 | |||
192 | idleconfig = STEPCONFIG_YNN | | ||
193 | STEPCONFIG_INM | | ||
194 | STEPCONFIG_YPN | STEPIDLE_INP; | ||
195 | tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig); | ||
196 | } | ||
197 | |||
198 | static void tscadc_read_coordinates(struct tscadc *ts_dev, | ||
199 | unsigned int *x, unsigned int *y) | ||
200 | { | ||
201 | unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT); | ||
202 | unsigned int prev_val_x = ~0, prev_val_y = ~0; | ||
203 | unsigned int prev_diff_x = ~0, prev_diff_y = ~0; | ||
204 | unsigned int read, diff; | ||
205 | unsigned int i; | ||
206 | |||
207 | /* | ||
208 | * Delta filter is used to remove large variations in sampled | ||
209 | * values from ADC. The filter tries to predict where the next | ||
210 | * coordinate could be. This is done by taking a previous | ||
211 | * coordinate and subtracting it form current one. Further the | ||
212 | * algorithm compares the difference with that of a present value, | ||
213 | * if true the value is reported to the sub system. | ||
214 | */ | ||
215 | for (i = 0; i < fifocount - 1; i++) { | ||
216 | read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
217 | diff = abs(read - prev_val_x); | ||
218 | if (diff < prev_diff_x) { | ||
219 | prev_diff_x = diff; | ||
220 | *x = read; | ||
221 | } | ||
222 | prev_val_x = read; | ||
223 | |||
224 | read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
225 | diff = abs(read - prev_val_y); | ||
226 | if (diff < prev_diff_y) { | ||
227 | prev_diff_y = diff; | ||
228 | *y = read; | ||
229 | } | ||
230 | prev_val_y = read; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static irqreturn_t tscadc_irq(int irq, void *dev) | ||
235 | { | ||
236 | struct tscadc *ts_dev = dev; | ||
237 | struct input_dev *input_dev = ts_dev->input; | ||
238 | unsigned int status, irqclr = 0; | ||
239 | unsigned int x = 0, y = 0; | ||
240 | unsigned int z1, z2, z; | ||
241 | unsigned int fsm; | ||
242 | |||
243 | status = tscadc_readl(ts_dev, REG_IRQSTATUS); | ||
244 | if (status & IRQENB_FIFO1THRES) { | ||
245 | tscadc_read_coordinates(ts_dev, &x, &y); | ||
246 | |||
247 | z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff; | ||
248 | z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff; | ||
249 | |||
250 | if (ts_dev->pen_down && z1 != 0 && z2 != 0) { | ||
251 | /* | ||
252 | * Calculate pressure using formula | ||
253 | * Resistance(touch) = x plate resistance * | ||
254 | * x postion/4096 * ((z2 / z1) - 1) | ||
255 | */ | ||
256 | z = z2 - z1; | ||
257 | z *= x; | ||
258 | z *= ts_dev->x_plate_resistance; | ||
259 | z /= z1; | ||
260 | z = (z + 2047) >> 12; | ||
261 | |||
262 | if (z <= MAX_12BIT) { | ||
263 | input_report_abs(input_dev, ABS_X, x); | ||
264 | input_report_abs(input_dev, ABS_Y, y); | ||
265 | input_report_abs(input_dev, ABS_PRESSURE, z); | ||
266 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
267 | input_sync(input_dev); | ||
268 | } | ||
269 | } | ||
270 | irqclr |= IRQENB_FIFO1THRES; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * Time for sequencer to settle, to read | ||
275 | * correct state of the sequencer. | ||
276 | */ | ||
277 | udelay(SEQ_SETTLE); | ||
278 | |||
279 | status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS); | ||
280 | if (status & IRQENB_PENUP) { | ||
281 | /* Pen up event */ | ||
282 | fsm = tscadc_readl(ts_dev, REG_ADCFSM); | ||
283 | if (fsm == ADCFSM_STEPID) { | ||
284 | ts_dev->pen_down = false; | ||
285 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
286 | input_report_abs(input_dev, ABS_PRESSURE, 0); | ||
287 | input_sync(input_dev); | ||
288 | } else { | ||
289 | ts_dev->pen_down = true; | ||
290 | } | ||
291 | irqclr |= IRQENB_PENUP; | ||
292 | } | ||
293 | |||
294 | tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr); | ||
295 | /* check pending interrupts */ | ||
296 | tscadc_writel(ts_dev, REG_IRQEOI, 0x0); | ||
297 | |||
298 | tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB); | ||
299 | return IRQ_HANDLED; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * The functions for inserting/removing driver as a module. | ||
304 | */ | ||
305 | |||
306 | static int tscadc_probe(struct platform_device *pdev) | ||
307 | { | ||
308 | const struct tsc_data *pdata = pdev->dev.platform_data; | ||
309 | struct resource *res; | ||
310 | struct tscadc *ts_dev; | ||
311 | struct input_dev *input_dev; | ||
312 | struct clk *clk; | ||
313 | int err; | ||
314 | int clk_value, ctrl, irq; | ||
315 | |||
316 | if (!pdata) { | ||
317 | dev_err(&pdev->dev, "missing platform data.\n"); | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
322 | if (!res) { | ||
323 | dev_err(&pdev->dev, "no memory resource defined.\n"); | ||
324 | return -EINVAL; | ||
325 | } | ||
326 | |||
327 | irq = platform_get_irq(pdev, 0); | ||
328 | if (irq < 0) { | ||
329 | dev_err(&pdev->dev, "no irq ID is specified.\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | /* Allocate memory for device */ | ||
334 | ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL); | ||
335 | input_dev = input_allocate_device(); | ||
336 | if (!ts_dev || !input_dev) { | ||
337 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
338 | err = -ENOMEM; | ||
339 | goto err_free_mem; | ||
340 | } | ||
341 | |||
342 | ts_dev->input = input_dev; | ||
343 | ts_dev->irq = irq; | ||
344 | ts_dev->wires = pdata->wires; | ||
345 | ts_dev->x_plate_resistance = pdata->x_plate_resistance; | ||
346 | |||
347 | res = request_mem_region(res->start, resource_size(res), pdev->name); | ||
348 | if (!res) { | ||
349 | dev_err(&pdev->dev, "failed to reserve registers.\n"); | ||
350 | err = -EBUSY; | ||
351 | goto err_free_mem; | ||
352 | } | ||
353 | |||
354 | ts_dev->tsc_base = ioremap(res->start, resource_size(res)); | ||
355 | if (!ts_dev->tsc_base) { | ||
356 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
357 | err = -ENOMEM; | ||
358 | goto err_release_mem_region; | ||
359 | } | ||
360 | |||
361 | err = request_irq(ts_dev->irq, tscadc_irq, | ||
362 | 0, pdev->dev.driver->name, ts_dev); | ||
363 | if (err) { | ||
364 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
365 | goto err_unmap_regs; | ||
366 | } | ||
367 | |||
368 | ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick"); | ||
369 | if (IS_ERR(ts_dev->tsc_ick)) { | ||
370 | dev_err(&pdev->dev, "failed to get TSC ick\n"); | ||
371 | goto err_free_irq; | ||
372 | } | ||
373 | clk_enable(ts_dev->tsc_ick); | ||
374 | |||
375 | clk = clk_get(&pdev->dev, "adc_tsc_fck"); | ||
376 | if (IS_ERR(clk)) { | ||
377 | dev_err(&pdev->dev, "failed to get TSC fck\n"); | ||
378 | err = PTR_ERR(clk); | ||
379 | goto err_disable_clk; | ||
380 | } | ||
381 | |||
382 | clk_value = clk_get_rate(clk) / ADC_CLK; | ||
383 | clk_put(clk); | ||
384 | |||
385 | if (clk_value < 7) { | ||
386 | dev_err(&pdev->dev, "clock input less than min clock requirement\n"); | ||
387 | goto err_disable_clk; | ||
388 | } | ||
389 | /* CLKDIV needs to be configured to the value minus 1 */ | ||
390 | tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1); | ||
391 | |||
392 | /* Enable wake-up of the SoC using touchscreen */ | ||
393 | tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB); | ||
394 | |||
395 | ctrl = CNTRLREG_STEPCONFIGWRT | | ||
396 | CNTRLREG_TSCENB | | ||
397 | CNTRLREG_STEPID; | ||
398 | switch (ts_dev->wires) { | ||
399 | case 4: | ||
400 | ctrl |= CNTRLREG_4WIRE; | ||
401 | break; | ||
402 | case 5: | ||
403 | ctrl |= CNTRLREG_5WIRE; | ||
404 | break; | ||
405 | case 8: | ||
406 | ctrl |= CNTRLREG_8WIRE; | ||
407 | break; | ||
408 | } | ||
409 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
410 | |||
411 | tscadc_idle_config(ts_dev); | ||
412 | tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES); | ||
413 | tscadc_step_config(ts_dev); | ||
414 | tscadc_writel(ts_dev, REG_FIFO1THR, 6); | ||
415 | |||
416 | ctrl |= CNTRLREG_TSCSSENB; | ||
417 | tscadc_writel(ts_dev, REG_CTRL, ctrl); | ||
418 | |||
419 | input_dev->name = "ti-tsc-adc"; | ||
420 | input_dev->dev.parent = &pdev->dev; | ||
421 | |||
422 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | ||
423 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | ||
424 | |||
425 | input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); | ||
426 | input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); | ||
427 | input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); | ||
428 | |||
429 | /* register to the input system */ | ||
430 | err = input_register_device(input_dev); | ||
431 | if (err) | ||
432 | goto err_disable_clk; | ||
433 | |||
434 | platform_set_drvdata(pdev, ts_dev); | ||
435 | return 0; | ||
436 | |||
437 | err_disable_clk: | ||
438 | clk_disable(ts_dev->tsc_ick); | ||
439 | clk_put(ts_dev->tsc_ick); | ||
440 | err_free_irq: | ||
441 | free_irq(ts_dev->irq, ts_dev); | ||
442 | err_unmap_regs: | ||
443 | iounmap(ts_dev->tsc_base); | ||
444 | err_release_mem_region: | ||
445 | release_mem_region(res->start, resource_size(res)); | ||
446 | err_free_mem: | ||
447 | input_free_device(input_dev); | ||
448 | kfree(ts_dev); | ||
449 | return err; | ||
450 | } | ||
451 | |||
452 | static int __devexit tscadc_remove(struct platform_device *pdev) | ||
453 | { | ||
454 | struct tscadc *ts_dev = platform_get_drvdata(pdev); | ||
455 | struct resource *res; | ||
456 | |||
457 | free_irq(ts_dev->irq, ts_dev); | ||
458 | |||
459 | input_unregister_device(ts_dev->input); | ||
460 | |||
461 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
462 | iounmap(ts_dev->tsc_base); | ||
463 | release_mem_region(res->start, resource_size(res)); | ||
464 | |||
465 | clk_disable(ts_dev->tsc_ick); | ||
466 | clk_put(ts_dev->tsc_ick); | ||
467 | |||
468 | kfree(ts_dev); | ||
469 | |||
470 | platform_set_drvdata(pdev, NULL); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static struct platform_driver ti_tsc_driver = { | ||
475 | .probe = tscadc_probe, | ||
476 | .remove = __devexit_p(tscadc_remove), | ||
477 | .driver = { | ||
478 | .name = "tsc", | ||
479 | .owner = THIS_MODULE, | ||
480 | }, | ||
481 | }; | ||
482 | module_platform_driver(ti_tsc_driver); | ||
483 | |||
484 | MODULE_DESCRIPTION("TI touchscreen controller driver"); | ||
485 | MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); | ||
486 | MODULE_LICENSE("GPL"); | ||