Root/target/linux/xburst/patches-3.0/0011-input-Add-touchscreen-driver-for-the-JZ4740-SoC.patch

1From 71e0648ad022c6f05e1bed1fcca69abc8abde4d9 Mon Sep 17 00:00:00 2001
2From: Lars-Peter Clausen <lars@metafoo.de>
3Date: Sun, 5 Sep 2010 20:45:08 +0200
4Subject: [PATCH 11/32] input: Add touchscreen driver for the JZ4740 SoC
5
6This patch adds a touchscreen driver for the Ingenic JZ4740 SoC.
7The touchscreen controller is part of the ADC unit and thus this driver is a mfd
8cell from the jz4740-adc driver.
9
10Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
11---
12 drivers/input/touchscreen/Kconfig | 12 ++
13 drivers/input/touchscreen/Makefile | 1 +
14 drivers/input/touchscreen/jz4740-ts.c | 330 +++++++++++++++++++++++++++++++++
15 3 files changed, 343 insertions(+), 0 deletions(-)
16 create mode 100644 drivers/input/touchscreen/jz4740-ts.c
17
18diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
19index cabd9e5..10836e5 100644
20--- a/drivers/input/touchscreen/Kconfig
21+++ b/drivers/input/touchscreen/Kconfig
22@@ -726,4 +726,16 @@ config TOUCHSCREEN_TPS6507X
23       To compile this driver as a module, choose M here: the
24       module will be called tps6507x_ts.
25 
26+config TOUCHSCREEN_JZ4740
27+ tristate "JZ4740 touchscreen support"
28+ depends on MFD_JZ4740_ADC
29+ help
30+ Say Y here if you want support for the touchscreen controller found on
31+ Ingenic JZ4740 SoCs.
32+
33+ If unsure, say N.
34+
35+ To compile this driver as a module, choose M here: the
36+ module will be called jz4740-ts.
37+
38 endif
39diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
40index 282d6f7..d8cc316 100644
41--- a/drivers/input/touchscreen/Makefile
42+++ b/drivers/input/touchscreen/Makefile
43@@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
44 obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
45 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
46 obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
47+obj-$(CONFIG_TOUCHSCREEN_JZ4740) += jz4740-ts.o
48 obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
49 obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
50 obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
51diff --git a/drivers/input/touchscreen/jz4740-ts.c b/drivers/input/touchscreen/jz4740-ts.c
52new file mode 100644
53index 0000000..dd5de34
54--- /dev/null
55+++ b/drivers/input/touchscreen/jz4740-ts.c
56@@ -0,0 +1,330 @@
57+/*
58+ * Touchscreen driver for Ingenic JZ SoCs.
59+ *
60+ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
61+ *
62+ * This program is free software; you can redistribute it and/or modify
63+ * it under the terms of the GNU General Public License version 2 as
64+ * published by the Free Software Foundation.
65+ *
66+ */
67+
68+#include <linux/interrupt.h>
69+#include <linux/kernel.h>
70+#include <linux/module.h>
71+#include <linux/platform_device.h>
72+#include <linux/slab.h>
73+
74+#include <linux/delay.h>
75+#include <linux/mfd/core.h>
76+#include <linux/input.h>
77+#include <linux/bitops.h>
78+#include <linux/jz4740-adc.h>
79+
80+struct jz4740_ts {
81+ struct platform_device *pdev;
82+
83+ struct resource *mem;
84+ void __iomem *base;
85+
86+ int irq_penup;
87+ int irq_pendown;
88+ int irq_data_ready;
89+
90+ struct mfd_cell *cell;
91+ struct input_dev *input;
92+
93+ bool is_open;
94+};
95+
96+static irqreturn_t jz4740_ts_data_ready_irq_handler(int irq, void *devid)
97+{
98+ struct jz4740_ts *jz4740_ts = devid;
99+ uint32_t data;
100+ unsigned long x, y, z1, z2, pressure;
101+
102+ data = readl(jz4740_ts->base + 0x08);
103+ x = data & 0xfff;
104+ y = (data >> 16) & 0xfff;
105+
106+ data = readl(jz4740_ts->base + 0x08);
107+ z1 = data & 0xfff;
108+ z2 = (data >> 16) & 0xfff;
109+ if (z1 == 0) {
110+ pressure = 4095UL;
111+ } else if (z1 > z2) {
112+ pressure = 0;
113+ } else {
114+ if (data & 0x8000)
115+ pressure = (((480UL * x * z2) / z1) - 480UL * x) / 4096UL;
116+ else
117+ pressure = (((272UL * y * z2) / z1) - 272UL * y) / 4096UL;
118+ if (pressure >= 4096UL)
119+ pressure = 4095UL;
120+ pressure = 4095UL - pressure;
121+ }
122+
123+ input_report_abs(jz4740_ts->input, ABS_X, y);
124+ input_report_abs(jz4740_ts->input, ABS_Y, 4095 - x);
125+ input_report_abs(jz4740_ts->input, ABS_PRESSURE, pressure);
126+ input_report_key(jz4740_ts->input, BTN_TOUCH, 1);
127+ input_sync(jz4740_ts->input);
128+
129+ return IRQ_HANDLED;
130+}
131+
132+static irqreturn_t jz4740_ts_pen_irq_handler(int irq, void *devid)
133+{
134+ struct jz4740_ts *jz4740_ts = devid;
135+ int is_pressed;
136+
137+ if (irq == jz4740_ts->irq_penup) {
138+ enable_irq(jz4740_ts->irq_pendown);
139+ is_pressed = 0;
140+ } else {
141+ enable_irq(jz4740_ts->irq_penup);
142+ is_pressed = 1;
143+ }
144+ disable_irq_nosync(irq);
145+
146+ printk("pen irq: %d\n", irq);
147+ input_report_key(jz4740_ts->input, BTN_TOUCH, is_pressed);
148+ if (is_pressed == 0)
149+ input_report_abs(jz4740_ts->input, ABS_PRESSURE, 0);
150+ input_sync(jz4740_ts->input);
151+
152+ return IRQ_HANDLED;
153+}
154+
155+static int jz4740_ts_open(struct input_dev *input)
156+{
157+ struct jz4740_ts *jz4740_ts = input_get_drvdata(input);
158+
159+ jz4740_ts->is_open = true;
160+ jz4740_ts->cell->enable(jz4740_ts->pdev);
161+
162+ return 0;
163+}
164+
165+static void jz4740_ts_close(struct input_dev *input)
166+{
167+ struct jz4740_ts *jz4740_ts = input_get_drvdata(input);
168+
169+ jz4740_ts->cell->disable(jz4740_ts->pdev);
170+ jz4740_ts->is_open = false;
171+}
172+
173+static int __devinit jz4740_ts_probe(struct platform_device *pdev)
174+{
175+ int ret = 0;
176+ struct jz4740_ts *jz4740_ts;
177+ struct input_dev *input;
178+
179+ jz4740_ts = kzalloc(sizeof(*jz4740_ts), GFP_KERNEL);
180+ if (!jz4740_ts) {
181+ dev_err(&pdev->dev, "Failed to allocate driver structure\n");
182+ return -ENOMEM;
183+ }
184+
185+ jz4740_ts->pdev = pdev;
186+ jz4740_ts->cell = pdev->dev.platform_data;
187+
188+ jz4740_ts->irq_data_ready = platform_get_irq(pdev, 0);
189+ if (jz4740_ts->irq_data_ready < 0) {
190+ ret = jz4740_ts->irq_data_ready;
191+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
192+ goto err_free;
193+ }
194+
195+ jz4740_ts->irq_penup = platform_get_irq(pdev, 1);
196+ if (jz4740_ts->irq_penup < 0) {
197+ ret = jz4740_ts->irq_penup;
198+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
199+ goto err_free;
200+ }
201+
202+ jz4740_ts->irq_pendown = platform_get_irq(pdev, 2);
203+ if (jz4740_ts->irq_pendown < 0) {
204+ ret = jz4740_ts->irq_pendown;
205+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
206+ goto err_free;
207+ }
208+
209+ jz4740_ts->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
210+ if (!jz4740_ts->mem) {
211+ ret = -ENOENT;
212+ dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
213+ goto err_free;
214+ }
215+
216+ jz4740_ts->mem = request_mem_region(jz4740_ts->mem->start,
217+ resource_size(jz4740_ts->mem), pdev->name);
218+ if (!jz4740_ts->mem) {
219+ ret = -EBUSY;
220+ dev_err(&pdev->dev, "Failed to request mmio memory region\n");
221+ goto err_free;
222+ }
223+
224+ jz4740_ts->base = ioremap_nocache(jz4740_ts->mem->start,
225+ resource_size(jz4740_ts->mem));
226+ if (!jz4740_ts->base) {
227+ ret = -EBUSY;
228+ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
229+ goto err_release_mem_region;
230+ }
231+
232+ input = input_allocate_device();
233+ if (!input) {
234+ dev_err(&pdev->dev, "Failed to allocate input device\n");
235+ ret = -ENOMEM;
236+ goto err_iounmap;
237+ }
238+
239+ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
240+ __set_bit(BTN_TOUCH, input->keybit);
241+
242+ input_set_abs_params(input, ABS_X, 150, 3920, 0, 0);
243+ input_set_abs_params(input, ABS_Y, 270, 3700, 0, 0);
244+ input_set_abs_params(input, ABS_PRESSURE, 0, 4096, 0, 0);
245+
246+ input->name = pdev->name;
247+ input->phys = "jz4740";
248+ input->id.bustype = BUS_HOST;
249+ input->dev.parent = &pdev->dev;
250+
251+ input->open = jz4740_ts_open;
252+ input->close = jz4740_ts_close;
253+
254+ input_set_drvdata(input, jz4740_ts);
255+
256+ ret = input_register_device(input);
257+ if (ret) {
258+ dev_err(&pdev->dev, "Failed to register input device: %d\n", ret);
259+ input_free_device(input);
260+ goto err_iounmap;
261+ }
262+ jz4740_ts->input = input;
263+
264+ ret = request_irq(jz4740_ts->irq_data_ready, jz4740_ts_data_ready_irq_handler, 0, pdev->name,
265+ jz4740_ts);
266+ if (ret) {
267+ dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
268+ goto err_input_unregister_device;
269+ }
270+ ret = request_irq(jz4740_ts->irq_penup, jz4740_ts_pen_irq_handler, 0, pdev->name,
271+ jz4740_ts);
272+ if (ret) {
273+ dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
274+ goto err_free_irq_data_ready;
275+ }
276+ disable_irq(jz4740_ts->irq_penup);
277+ ret = request_irq(jz4740_ts->irq_pendown, jz4740_ts_pen_irq_handler, 0, pdev->name,
278+ jz4740_ts);
279+ if (ret) {
280+ dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
281+ goto err_free_irq_penup;
282+ }
283+ platform_set_drvdata(pdev, jz4740_ts);
284+
285+ jz4740_adc_set_config(pdev->dev.parent,
286+ JZ_ADC_CONFIG_EX_IN | JZ_ADC_CONFIG_XYZ_OFFSET(2) | JZ_ADC_CONFIG_DNUM(7),
287+ JZ_ADC_CONFIG_EX_IN | JZ_ADC_CONFIG_XYZ_MASK | JZ_ADC_CONFIG_DNUM_MASK);
288+
289+
290+ writel(0x15e, jz4740_ts->base);
291+ writel(0x32, jz4740_ts->base + 0x04);
292+
293+ return 0;
294+
295+err_free_irq_penup:
296+ free_irq(jz4740_ts->irq_penup, jz4740_ts);
297+err_free_irq_data_ready:
298+ free_irq(jz4740_ts->irq_data_ready, jz4740_ts);
299+err_input_unregister_device:
300+ input_unregister_device(jz4740_ts->input);
301+err_iounmap:
302+ platform_set_drvdata(pdev, NULL);
303+ iounmap(jz4740_ts->base);
304+err_release_mem_region:
305+ release_mem_region(jz4740_ts->mem->start, resource_size(jz4740_ts->mem));
306+err_free:
307+ kfree(jz4740_ts);
308+ return ret;
309+}
310+
311+static int __devexit jz4740_ts_remove(struct platform_device *pdev)
312+{
313+ struct jz4740_ts *jz4740_ts = platform_get_drvdata(pdev);
314+
315+
316+ free_irq(jz4740_ts->irq_pendown, jz4740_ts);
317+ free_irq(jz4740_ts->irq_penup, jz4740_ts);
318+ free_irq(jz4740_ts->irq_data_ready, jz4740_ts);
319+
320+ input_unregister_device(jz4740_ts->input);
321+
322+ iounmap(jz4740_ts->base);
323+ release_mem_region(jz4740_ts->mem->start, resource_size(jz4740_ts->mem));
324+
325+ kfree(jz4740_ts);
326+
327+ return 0;
328+}
329+
330+#ifdef CONFIG_PM
331+static int jz4740_ts_suspend(struct device *dev)
332+{
333+ struct jz4740_ts *jz4740_ts = dev_get_drvdata(dev);
334+
335+ if (jz4740_ts->is_open);
336+ jz4740_ts->cell->disable(jz4740_ts->pdev);
337+
338+ return 0;
339+}
340+
341+static int jz4740_ts_resume(struct device *dev)
342+{
343+ struct jz4740_ts *jz4740_ts = dev_get_drvdata(dev);
344+
345+ if (jz4740_ts->is_open);
346+ jz4740_ts->cell->enable(jz4740_ts->pdev);
347+
348+ return 0;
349+}
350+
351+static const struct dev_pm_ops jz4740_ts_pm_ops = {
352+ .suspend = jz4740_ts_suspend,
353+ .resume = jz4740_ts_resume,
354+};
355+
356+#define JZ4740_TS_PM_OPS (&jz4740_ts_pm_ops)
357+#else
358+#define JZ4740_TS_PM_OPS NULL
359+#endif
360+
361+static struct platform_driver jz4740_ts_driver = {
362+ .probe = jz4740_ts_probe,
363+ .remove = __devexit_p(jz4740_ts_remove),
364+ .driver = {
365+ .name = "jz4740-ts",
366+ .owner = THIS_MODULE,
367+ .pm = JZ4740_TS_PM_OPS,
368+ },
369+};
370+
371+static int __init jz4740_ts_init(void)
372+{
373+ return platform_driver_register(&jz4740_ts_driver);
374+}
375+module_init(jz4740_ts_init);
376+
377+static void __exit jz4740_ts_exit(void)
378+{
379+ platform_driver_unregister(&jz4740_ts_driver);
380+}
381+module_exit(jz4740_ts_exit);
382+
383+MODULE_ALIAS("platform:jz4740-ts");
384+MODULE_LICENSE("GPL");
385+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
386+MODULE_DESCRIPTION("JZ4740 SoC battery driver");
387--
3881.7.4.1
389
390

Archive Download this file



interactive