mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-01 10:33:27 +00:00
input: touchscreen: Add MSM legacy touchscreen driver
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
This commit is contained in:
parent
1d00aa918b
commit
b7a7545d59
4 changed files with 365 additions and 0 deletions
26
arch/arm/mach-msm/include/mach/msm_touch.h
Normal file
26
arch/arm/mach-msm/include/mach/msm_touch.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* arch/arm/mach-msm/include/mach/msm_touch.h
|
||||
*
|
||||
* Platform data for MSM touchscreen driver.
|
||||
*
|
||||
* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MACH_MSM_TOUCH_H_
|
||||
#define _MACH_MSM_TOUCH_H_
|
||||
|
||||
struct msm_ts_platform_data {
|
||||
unsigned int x_max;
|
||||
unsigned int y_max;
|
||||
unsigned int pressure_max;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -868,6 +868,27 @@ config TOUCHSCREEN_TSC2007
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called tsc2007.
|
||||
|
||||
config TOUCHSCREEN_MSM_LEGACY
|
||||
default n
|
||||
tristate "MSM Touchscreen"
|
||||
depends on ARCH_MSM && !ARCH_MSM7X30
|
||||
help
|
||||
Say Y here if you have a touchscreen interface using MSM
|
||||
touchscreen controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called msm_touch.
|
||||
|
||||
config ANDROID_TOUCHSCREEN_MSM_HACKS
|
||||
default y
|
||||
depends on TOUCHSCREEN_MSM_LEGACY
|
||||
bool "Android MSM Touchscreen hacks"
|
||||
help
|
||||
Say Y here if you are running Android framework on Qualcomm
|
||||
MSM/QSD based Surf or FFAs. These hacks are required inorder
|
||||
to Android framework to receive adjusted x, y co-ordinates
|
||||
until proper calibration framework is in place.
|
||||
|
||||
config TOUCHSCREEN_W90X900
|
||||
tristate "W90P910 touchscreen driver"
|
||||
depends on HAVE_CLK
|
||||
|
|
|
@ -76,5 +76,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_MSM_LEGACY) += msm_touch.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CY8C_TS) += cy8c_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C_QC) += cyttsp-i2c-qc.o
|
||||
|
|
317
drivers/input/touchscreen/msm_touch.c
Normal file
317
drivers/input/touchscreen/msm_touch.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
/* drivers/input/touchscreen/msm_touch.c
|
||||
*
|
||||
* Copyright (c) 2008-2009, 2011, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/msm_touch.h>
|
||||
|
||||
/* HW register map */
|
||||
#define TSSC_CTL_REG 0x100
|
||||
#define TSSC_SI_REG 0x108
|
||||
#define TSSC_OPN_REG 0x104
|
||||
#define TSSC_STATUS_REG 0x10C
|
||||
#define TSSC_AVG12_REG 0x110
|
||||
|
||||
/* status bits */
|
||||
#define TSSC_STS_OPN_SHIFT 0x6
|
||||
#define TSSC_STS_OPN_BMSK 0x1C0
|
||||
#define TSSC_STS_NUMSAMP_SHFT 0x1
|
||||
#define TSSC_STS_NUMSAMP_BMSK 0x3E
|
||||
|
||||
/* CTL bits */
|
||||
#define TSSC_CTL_EN (0x1 << 0)
|
||||
#define TSSC_CTL_SW_RESET (0x1 << 2)
|
||||
#define TSSC_CTL_MASTER_MODE (0x3 << 3)
|
||||
#define TSSC_CTL_AVG_EN (0x1 << 5)
|
||||
#define TSSC_CTL_DEB_EN (0x1 << 6)
|
||||
#define TSSC_CTL_DEB_12_MS (0x2 << 7) /* 1.2 ms */
|
||||
#define TSSC_CTL_DEB_16_MS (0x3 << 7) /* 1.6 ms */
|
||||
#define TSSC_CTL_DEB_2_MS (0x4 << 7) /* 2 ms */
|
||||
#define TSSC_CTL_DEB_3_MS (0x5 << 7) /* 3 ms */
|
||||
#define TSSC_CTL_DEB_4_MS (0x6 << 7) /* 4 ms */
|
||||
#define TSSC_CTL_DEB_6_MS (0x7 << 7) /* 6 ms */
|
||||
#define TSSC_CTL_INTR_FLAG1 (0x1 << 10)
|
||||
#define TSSC_CTL_DATA (0x1 << 11)
|
||||
#define TSSC_CTL_SSBI_CTRL_EN (0x1 << 13)
|
||||
|
||||
/* control reg's default state */
|
||||
#define TSSC_CTL_STATE ( \
|
||||
TSSC_CTL_DEB_12_MS | \
|
||||
TSSC_CTL_DEB_EN | \
|
||||
TSSC_CTL_AVG_EN | \
|
||||
TSSC_CTL_MASTER_MODE | \
|
||||
TSSC_CTL_EN)
|
||||
|
||||
#define TSSC_NUMBER_OF_OPERATIONS 2
|
||||
#define TS_PENUP_TIMEOUT_MS 20
|
||||
|
||||
#define TS_DRIVER_NAME "msm_touchscreen"
|
||||
|
||||
#define X_MAX 1024
|
||||
#define Y_MAX 1024
|
||||
#define P_MAX 256
|
||||
|
||||
struct ts {
|
||||
struct input_dev *input;
|
||||
struct timer_list timer;
|
||||
int irq;
|
||||
unsigned int x_max;
|
||||
unsigned int y_max;
|
||||
};
|
||||
|
||||
static void __iomem *virt;
|
||||
#define TSSC_REG(reg) (virt + TSSC_##reg##_REG)
|
||||
|
||||
static void ts_update_pen_state(struct ts *ts, int x, int y, int pressure)
|
||||
{
|
||||
if (pressure) {
|
||||
input_report_abs(ts->input, ABS_X, x);
|
||||
input_report_abs(ts->input, ABS_Y, y);
|
||||
input_report_abs(ts->input, ABS_PRESSURE, pressure);
|
||||
input_report_key(ts->input, BTN_TOUCH, !!pressure);
|
||||
} else {
|
||||
input_report_abs(ts->input, ABS_PRESSURE, 0);
|
||||
input_report_key(ts->input, BTN_TOUCH, 0);
|
||||
}
|
||||
|
||||
input_sync(ts->input);
|
||||
}
|
||||
|
||||
static void ts_timer(unsigned long arg)
|
||||
{
|
||||
struct ts *ts = (struct ts *)arg;
|
||||
|
||||
ts_update_pen_state(ts, 0, 0, 0);
|
||||
}
|
||||
|
||||
static irqreturn_t ts_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
u32 avgs, x, y, lx, ly;
|
||||
u32 num_op, num_samp;
|
||||
u32 status;
|
||||
|
||||
struct ts *ts = dev_id;
|
||||
|
||||
status = readl_relaxed(TSSC_REG(STATUS));
|
||||
avgs = readl_relaxed(TSSC_REG(AVG12));
|
||||
x = avgs & 0xFFFF;
|
||||
y = avgs >> 16;
|
||||
|
||||
/* For pen down make sure that the data just read is still valid.
|
||||
* The DATA bit will still be set if the ARM9 hasn't clobbered
|
||||
* the TSSC. If it's not set, then it doesn't need to be cleared
|
||||
* here, so just return.
|
||||
*/
|
||||
if (!(readl_relaxed(TSSC_REG(CTL)) & TSSC_CTL_DATA))
|
||||
goto out;
|
||||
|
||||
/* Data has been read, OK to clear the data flag */
|
||||
writel_relaxed(TSSC_CTL_STATE, TSSC_REG(CTL));
|
||||
/* barrier: Write to complete before the next sample */
|
||||
mb();
|
||||
/* Valid samples are indicated by the sample number in the status
|
||||
* register being the number of expected samples and the number of
|
||||
* samples collected being zero (this check is due to ADC contention).
|
||||
*/
|
||||
num_op = (status & TSSC_STS_OPN_BMSK) >> TSSC_STS_OPN_SHIFT;
|
||||
num_samp = (status & TSSC_STS_NUMSAMP_BMSK) >> TSSC_STS_NUMSAMP_SHFT;
|
||||
|
||||
if ((num_op == TSSC_NUMBER_OF_OPERATIONS) && (num_samp == 0)) {
|
||||
/* TSSC can do Z axis measurment, but driver doesn't support
|
||||
* this yet.
|
||||
*/
|
||||
|
||||
/*
|
||||
* REMOVE THIS:
|
||||
* These x, y co-ordinates adjustments will be removed once
|
||||
* Android framework adds calibration framework.
|
||||
*/
|
||||
#ifdef CONFIG_ANDROID_TOUCHSCREEN_MSM_HACKS
|
||||
lx = ts->x_max - x;
|
||||
ly = ts->y_max - y;
|
||||
#else
|
||||
lx = x;
|
||||
ly = y;
|
||||
#endif
|
||||
ts_update_pen_state(ts, lx, ly, 255);
|
||||
/* kick pen up timer - to make sure it expires again(!) */
|
||||
mod_timer(&ts->timer,
|
||||
jiffies + msecs_to_jiffies(TS_PENUP_TIMEOUT_MS));
|
||||
|
||||
} else
|
||||
printk(KERN_INFO "Ignored interrupt: {%3d, %3d},"
|
||||
" op = %3d samp = %3d\n",
|
||||
x, y, num_op, num_samp);
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
int result;
|
||||
struct input_dev *input_dev;
|
||||
struct resource *res, *ioarea;
|
||||
struct ts *ts;
|
||||
unsigned int x_max, y_max, pressure_max;
|
||||
struct msm_ts_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
/* The primary initialization of the TS Hardware
|
||||
* is taken care of by the ADC code on the modem side
|
||||
*/
|
||||
|
||||
ts = kzalloc(sizeof(struct ts), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev || !ts) {
|
||||
result = -ENOMEM;
|
||||
goto fail_alloc_mem;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
|
||||
result = -ENOENT;
|
||||
goto fail_alloc_mem;
|
||||
}
|
||||
|
||||
ts->irq = platform_get_irq(pdev, 0);
|
||||
if (!ts->irq) {
|
||||
dev_err(&pdev->dev, "Could not get IORESOURCE_IRQ\n");
|
||||
result = -ENODEV;
|
||||
goto fail_alloc_mem;
|
||||
}
|
||||
|
||||
ioarea = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!ioarea) {
|
||||
dev_err(&pdev->dev, "Could not allocate io region\n");
|
||||
result = -EBUSY;
|
||||
goto fail_alloc_mem;
|
||||
}
|
||||
|
||||
virt = ioremap(res->start, resource_size(res));
|
||||
if (!virt) {
|
||||
dev_err(&pdev->dev, "Could not ioremap region\n");
|
||||
result = -ENOMEM;
|
||||
goto fail_ioremap;
|
||||
}
|
||||
|
||||
input_dev->name = TS_DRIVER_NAME;
|
||||
input_dev->phys = "msm_touch/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0x0001;
|
||||
input_dev->id.product = 0x0002;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
|
||||
input_dev->absbit[BIT_WORD(ABS_MISC)] = BIT_MASK(ABS_MISC);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
if (pdata) {
|
||||
x_max = pdata->x_max ? : X_MAX;
|
||||
y_max = pdata->y_max ? : Y_MAX;
|
||||
pressure_max = pdata->pressure_max ? : P_MAX;
|
||||
} else {
|
||||
x_max = X_MAX;
|
||||
y_max = Y_MAX;
|
||||
pressure_max = P_MAX;
|
||||
}
|
||||
|
||||
ts->x_max = x_max;
|
||||
ts->y_max = y_max;
|
||||
|
||||
input_set_abs_params(input_dev, ABS_X, 0, x_max, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, y_max, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, pressure_max, 0, 0);
|
||||
|
||||
result = input_register_device(input_dev);
|
||||
if (result)
|
||||
goto fail_ip_reg;
|
||||
|
||||
ts->input = input_dev;
|
||||
|
||||
setup_timer(&ts->timer, ts_timer, (unsigned long)ts);
|
||||
result = request_irq(ts->irq, ts_interrupt, IRQF_TRIGGER_RISING,
|
||||
"touchscreen", ts);
|
||||
if (result)
|
||||
goto fail_req_irq;
|
||||
|
||||
platform_set_drvdata(pdev, ts);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_req_irq:
|
||||
input_unregister_device(input_dev);
|
||||
input_dev = NULL;
|
||||
fail_ip_reg:
|
||||
iounmap(virt);
|
||||
fail_ioremap:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
fail_alloc_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ts);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct ts *ts = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(ts->irq, ts);
|
||||
del_timer_sync(&ts->timer);
|
||||
|
||||
input_unregister_device(ts->input);
|
||||
iounmap(virt);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ts_driver = {
|
||||
.probe = ts_probe,
|
||||
.remove = ts_remove,
|
||||
.driver = {
|
||||
.name = TS_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ts_init(void)
|
||||
{
|
||||
return platform_driver_register(&ts_driver);
|
||||
}
|
||||
module_init(ts_init);
|
||||
|
||||
static void __exit ts_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ts_driver);
|
||||
}
|
||||
module_exit(ts_exit);
|
||||
|
||||
MODULE_DESCRIPTION("MSM Touch Screen driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:msm_touchscreen");
|
Loading…
Reference in a new issue