diff options
Diffstat (limited to 'target/linux/xburst/patches-2.6.36/061-touchscreen.patch')
-rw-r--r-- | target/linux/xburst/patches-2.6.36/061-touchscreen.patch | 379 |
1 files changed, 379 insertions, 0 deletions
diff --git a/target/linux/xburst/patches-2.6.36/061-touchscreen.patch b/target/linux/xburst/patches-2.6.36/061-touchscreen.patch new file mode 100644 index 0000000000..f90e69c285 --- /dev/null +++ b/target/linux/xburst/patches-2.6.36/061-touchscreen.patch @@ -0,0 +1,379 @@ +From 499be7c13f157eb6ecf93b8b8187a67d61f0f3d6 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen <lars@metafoo.de> +Date: Sun, 5 Sep 2010 20:45:08 +0200 +Subject: [PATCH] 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> +--- + drivers/input/touchscreen/Kconfig | 12 ++ + drivers/input/touchscreen/Makefile | 1 + + drivers/input/touchscreen/jz4740-ts.c | 330 +++++++++++++++++++++++++++++++++ + 3 files changed, 343 insertions(+), 0 deletions(-) + create mode 100644 drivers/input/touchscreen/jz4740-ts.c + +--- a/drivers/input/touchscreen/Kconfig ++++ b/drivers/input/touchscreen/Kconfig +@@ -638,4 +638,16 @@ config TOUCHSCREEN_STMPE + To compile this driver as a module, choose M here: the + module will be called stmpe-ts. + ++config TOUCHSCREEN_JZ4740 ++ tristate "JZ4740 touchscreen support" ++ depends on MFD_JZ4740_ADC ++ help ++ Say Y here if you want support for the touchscreen controller found on ++ Ingenic JZ4740 SoCs. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called jz4740-ts. ++ + endif +--- a/drivers/input/touchscreen/Makefile ++++ b/drivers/input/touchscreen/Makefile +@@ -23,6 +23,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ + obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o + obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o + obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o ++obj-$(CONFIG_TOUCHSCREEN_JZ4740) += jz4740-ts.o + obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o + obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o + obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o +--- /dev/null ++++ b/drivers/input/touchscreen/jz4740-ts.c +@@ -0,0 +1,330 @@ ++/* ++ * Touchscreen driver for Ingenic JZ SoCs. ++ * ++ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/interrupt.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++ ++#include <linux/delay.h> ++#include <linux/mfd/core.h> ++#include <linux/input.h> ++#include <linux/bitops.h> ++#include <linux/jz4740-adc.h> ++ ++struct jz4740_ts { ++ struct platform_device *pdev; ++ ++ struct resource *mem; ++ void __iomem *base; ++ ++ int irq_penup; ++ int irq_pendown; ++ int irq_data_ready; ++ ++ struct mfd_cell *cell; ++ struct input_dev *input; ++ ++ bool is_open; ++}; ++ ++static irqreturn_t jz4740_ts_data_ready_irq_handler(int irq, void *devid) ++{ ++ struct jz4740_ts *jz4740_ts = devid; ++ uint32_t data; ++ unsigned long x, y, z1, z2, pressure; ++ ++ data = readl(jz4740_ts->base + 0x08); ++ x = data & 0xfff; ++ y = (data >> 16) & 0xfff; ++ ++ data = readl(jz4740_ts->base + 0x08); ++ z1 = data & 0xfff; ++ z2 = (data >> 16) & 0xfff; ++ if (z1 == 0) { ++ pressure = 4095UL; ++ } else if (z1 > z2) { ++ pressure = 0; ++ } else { ++ if (data & 0x8000) ++ pressure = (((480UL * x * z2) / z1) - 480UL * x) / 4096UL; ++ else ++ pressure = (((272UL * y * z2) / z1) - 272UL * y) / 4096UL; ++ if (pressure >= 4096UL) ++ pressure = 4095UL; ++ pressure = 4095UL - pressure; ++ } ++ ++ input_report_abs(jz4740_ts->input, ABS_X, y); ++ input_report_abs(jz4740_ts->input, ABS_Y, 4095 - x); ++ input_report_abs(jz4740_ts->input, ABS_PRESSURE, pressure); ++ input_report_key(jz4740_ts->input, BTN_TOUCH, 1); ++ input_sync(jz4740_ts->input); ++ ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t jz4740_ts_pen_irq_handler(int irq, void *devid) ++{ ++ struct jz4740_ts *jz4740_ts = devid; ++ int is_pressed; ++ ++ if (irq == jz4740_ts->irq_penup) { ++ enable_irq(jz4740_ts->irq_pendown); ++ is_pressed = 0; ++ } else { ++ enable_irq(jz4740_ts->irq_penup); ++ is_pressed = 1; ++ } ++ disable_irq_nosync(irq); ++ ++ printk("pen irq: %d\n", irq); ++ input_report_key(jz4740_ts->input, BTN_TOUCH, is_pressed); ++ if (is_pressed == 0) ++ input_report_abs(jz4740_ts->input, ABS_PRESSURE, 0); ++ input_sync(jz4740_ts->input); ++ ++ return IRQ_HANDLED; ++} ++ ++static int jz4740_ts_open(struct input_dev *input) ++{ ++ struct jz4740_ts *jz4740_ts = input_get_drvdata(input); ++ ++ jz4740_ts->is_open = true; ++ jz4740_ts->cell->enable(jz4740_ts->pdev); ++ ++ return 0; ++} ++ ++static void jz4740_ts_close(struct input_dev *input) ++{ ++ struct jz4740_ts *jz4740_ts = input_get_drvdata(input); ++ ++ jz4740_ts->cell->disable(jz4740_ts->pdev); ++ jz4740_ts->is_open = false; ++} ++ ++static int __devinit jz4740_ts_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ struct jz4740_ts *jz4740_ts; ++ struct input_dev *input; ++ ++ jz4740_ts = kzalloc(sizeof(*jz4740_ts), GFP_KERNEL); ++ if (!jz4740_ts) { ++ dev_err(&pdev->dev, "Failed to allocate driver structure\n"); ++ return -ENOMEM; ++ } ++ ++ jz4740_ts->pdev = pdev; ++ jz4740_ts->cell = pdev->dev.platform_data; ++ ++ jz4740_ts->irq_data_ready = platform_get_irq(pdev, 0); ++ if (jz4740_ts->irq_data_ready < 0) { ++ ret = jz4740_ts->irq_data_ready; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ jz4740_ts->irq_penup = platform_get_irq(pdev, 1); ++ if (jz4740_ts->irq_penup < 0) { ++ ret = jz4740_ts->irq_penup; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ jz4740_ts->irq_pendown = platform_get_irq(pdev, 2); ++ if (jz4740_ts->irq_pendown < 0) { ++ ret = jz4740_ts->irq_pendown; ++ dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); ++ goto err_free; ++ } ++ ++ jz4740_ts->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!jz4740_ts->mem) { ++ ret = -ENOENT; ++ dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); ++ goto err_free; ++ } ++ ++ jz4740_ts->mem = request_mem_region(jz4740_ts->mem->start, ++ resource_size(jz4740_ts->mem), pdev->name); ++ if (!jz4740_ts->mem) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to request mmio memory region\n"); ++ goto err_free; ++ } ++ ++ jz4740_ts->base = ioremap_nocache(jz4740_ts->mem->start, ++ resource_size(jz4740_ts->mem)); ++ if (!jz4740_ts->base) { ++ ret = -EBUSY; ++ dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); ++ goto err_release_mem_region; ++ } ++ ++ input = input_allocate_device(); ++ if (!input) { ++ dev_err(&pdev->dev, "Failed to allocate input device\n"); ++ ret = -ENOMEM; ++ goto err_iounmap; ++ } ++ ++ input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ++ __set_bit(BTN_TOUCH, input->keybit); ++ ++ input_set_abs_params(input, ABS_X, 150, 3920, 0, 0); ++ input_set_abs_params(input, ABS_Y, 270, 3700, 0, 0); ++ input_set_abs_params(input, ABS_PRESSURE, 0, 4096, 0, 0); ++ ++ input->name = pdev->name; ++ input->phys = "jz4740"; ++ input->id.bustype = BUS_HOST; ++ input->dev.parent = &pdev->dev; ++ ++ input->open = jz4740_ts_open; ++ input->close = jz4740_ts_close; ++ ++ input_set_drvdata(input, jz4740_ts); ++ ++ ret = input_register_device(input); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to register input device: %d\n", ret); ++ input_free_device(input); ++ goto err_iounmap; ++ } ++ jz4740_ts->input = input; ++ ++ ret = request_irq(jz4740_ts->irq_data_ready, jz4740_ts_data_ready_irq_handler, 0, pdev->name, ++ jz4740_ts); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d\n", ret); ++ goto err_input_unregister_device; ++ } ++ ret = request_irq(jz4740_ts->irq_penup, jz4740_ts_pen_irq_handler, 0, pdev->name, ++ jz4740_ts); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d\n", ret); ++ goto err_free_irq_data_ready; ++ } ++ disable_irq(jz4740_ts->irq_penup); ++ ret = request_irq(jz4740_ts->irq_pendown, jz4740_ts_pen_irq_handler, 0, pdev->name, ++ jz4740_ts); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to request irq %d\n", ret); ++ goto err_free_irq_penup; ++ } ++ platform_set_drvdata(pdev, jz4740_ts); ++ ++ jz4740_adc_set_config(pdev->dev.parent, ++ JZ_ADC_CONFIG_EX_IN | JZ_ADC_CONFIG_XYZ_OFFSET(2) | JZ_ADC_CONFIG_DNUM(7), ++ JZ_ADC_CONFIG_EX_IN | JZ_ADC_CONFIG_XYZ_MASK | JZ_ADC_CONFIG_DNUM_MASK); ++ ++ ++ writel(0x15e, jz4740_ts->base); ++ writel(0x32, jz4740_ts->base + 0x04); ++ ++ return 0; ++ ++err_free_irq_penup: ++ free_irq(jz4740_ts->irq_penup, jz4740_ts); ++err_free_irq_data_ready: ++ free_irq(jz4740_ts->irq_data_ready, jz4740_ts); ++err_input_unregister_device: ++ input_unregister_device(jz4740_ts->input); ++err_iounmap: ++ platform_set_drvdata(pdev, NULL); ++ iounmap(jz4740_ts->base); ++err_release_mem_region: ++ release_mem_region(jz4740_ts->mem->start, resource_size(jz4740_ts->mem)); ++err_free: ++ kfree(jz4740_ts); ++ return ret; ++} ++ ++static int __devexit jz4740_ts_remove(struct platform_device *pdev) ++{ ++ struct jz4740_ts *jz4740_ts = platform_get_drvdata(pdev); ++ ++ ++ free_irq(jz4740_ts->irq_pendown, jz4740_ts); ++ free_irq(jz4740_ts->irq_penup, jz4740_ts); ++ free_irq(jz4740_ts->irq_data_ready, jz4740_ts); ++ ++ input_unregister_device(jz4740_ts->input); ++ ++ iounmap(jz4740_ts->base); ++ release_mem_region(jz4740_ts->mem->start, resource_size(jz4740_ts->mem)); ++ ++ kfree(jz4740_ts); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int jz4740_ts_suspend(struct device *dev) ++{ ++ struct jz4740_ts *jz4740_ts = dev_get_drvdata(dev); ++ ++ if (jz4740_ts->is_open); ++ jz4740_ts->cell->disable(jz4740_ts->pdev); ++ ++ return 0; ++} ++ ++static int jz4740_ts_resume(struct device *dev) ++{ ++ struct jz4740_ts *jz4740_ts = dev_get_drvdata(dev); ++ ++ if (jz4740_ts->is_open); ++ jz4740_ts->cell->enable(jz4740_ts->pdev); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops jz4740_ts_pm_ops = { ++ .suspend = jz4740_ts_suspend, ++ .resume = jz4740_ts_resume, ++}; ++ ++#define JZ4740_TS_PM_OPS (&jz4740_ts_pm_ops) ++#else ++#define JZ4740_TS_PM_OPS NULL ++#endif ++ ++static struct platform_driver jz4740_ts_driver = { ++ .probe = jz4740_ts_probe, ++ .remove = __devexit_p(jz4740_ts_remove), ++ .driver = { ++ .name = "jz4740-ts", ++ .owner = THIS_MODULE, ++ .pm = JZ4740_TS_PM_OPS, ++ }, ++}; ++ ++static int __init jz4740_ts_init(void) ++{ ++ return platform_driver_register(&jz4740_ts_driver); ++} ++module_init(jz4740_ts_init); ++ ++static void __exit jz4740_ts_exit(void) ++{ ++ platform_driver_unregister(&jz4740_ts_driver); ++} ++module_exit(jz4740_ts_exit); ++ ++MODULE_ALIAS("platform:jz4740-ts"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); ++MODULE_DESCRIPTION("JZ4740 SoC battery driver"); |