Date:2010-09-05 20:45:08 (13 years 6 months ago)
Author:Lars C.
Commit:dc7f0a5b12cc8dd7e0a5e8045f1a6cc55e35198f
Message:input: Add touchscreen driver for the JZ4740 SoC

This patch adds a touchscreen driver for the Ingenic JZ4740 SoC.
The touchscreen controller is part of the ADC unit and thus this driver is a mfd
cell from the jz4740-adc driver.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Files: drivers/input/touchscreen/Kconfig (1 diff)
drivers/input/touchscreen/Makefile (1 diff)
drivers/input/touchscreen/jz4740-ts.c (1 diff)

Change Details

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

Archive Download the corresponding diff file



interactive