Commit 6425efa7 authored by Tony Lindgren's avatar Tony Lindgren

Add various OMAP input drivers

Adds various OMAP input drivers.
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 2971216f
...@@ -183,3 +183,23 @@ config KEYBOARD_HIL ...@@ -183,3 +183,23 @@ config KEYBOARD_HIL
to your machine, so normally you should say Y here. to your machine, so normally you should say Y here.
endif endif
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1510 || ARCH_OMAP16XX) && INPUT && INPUT_KEYBOARD
help
Say Y here if you want to use the OMAP keypad.
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
config OMAP_PS2
tristate "TI OMAP Innovator 1510 PS/2 keyboard & mouse support"
depends on ARCH_OMAP1510 && MACH_OMAP_INNOVATOR && INPUT && INPUT_KEYBOARD
help
Say Y here if you want to use the OMAP Innovator 1510 PS/2
keyboard and mouse.
To compile this driver as a module, choose M here: the
module will be called innovator_ps2.
...@@ -16,4 +16,5 @@ obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o ...@@ -16,4 +16,5 @@ obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_OMAP_PS2) += innovator_ps2.o
This diff is collapsed.
/*
* linux/drivers/char/omap-keypad.c
*
* OMAP Keypad Driver
*
* Copyright (C) 2003 Nokia Corporation
* Written by Timo Ters <ext-timo.teras@nokia.com>
*
* Added support for H2 & H3 Keypad
* Copyright (C) 2004 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <asm/arch/irqs.h>
#include <asm/arch/gpio.h>
#include <asm/arch/hardware.h>
#include <asm/io.h>
#include <asm/errno.h>
#include <asm/mach-types.h>
#include <asm/arch/mux.h>
#undef NEW_BOARD_LEARNING_MODE
static void omap_kp_tasklet(unsigned long);
static void omap_kp_timer(unsigned long);
static struct input_dev omap_kp_dev;
static unsigned char keypad_state[8];
static struct timer_list kp_timer;
DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
static int h2_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_3),
KEY(0, 3, KEY_F10),
KEY(0, 4, KEY_F5),
KEY(0, 5, KEY_9),
KEY(1, 0, KEY_DOWN),
KEY(1, 1, KEY_UP),
KEY(1, 2, KEY_2),
KEY(1, 3, KEY_F9),
KEY(1, 4, KEY_F7),
KEY(1, 5, KEY_0),
KEY(2, 0, KEY_ENTER),
KEY(2, 1, KEY_6),
KEY(2, 2, KEY_1),
KEY(2, 3, KEY_F2),
KEY(2, 4, KEY_F6),
KEY(2, 5, KEY_HOME),
KEY(3, 0, KEY_8),
KEY(3, 1, KEY_5),
KEY(3, 2, KEY_F12),
KEY(3, 3, KEY_F3),
KEY(3, 4, KEY_F8),
KEY(3, 5, KEY_END),
KEY(4, 0, KEY_7),
KEY(4, 1, KEY_4),
KEY(4, 2, KEY_F11),
KEY(4, 3, KEY_F1),
KEY(4, 4, KEY_F4),
KEY(4, 5, KEY_ESC),
KEY(5, 0, KEY_F13),
KEY(5, 1, KEY_F14),
KEY(5, 2, KEY_F15),
KEY(5, 3, KEY_F16),
KEY(5, 4, KEY_SLEEP),
0
};
static int test_keymap[] = {
KEY(0, 0, KEY_F4),
KEY(1, 0, KEY_LEFT),
KEY(2, 0, KEY_F1),
KEY(0, 1, KEY_DOWN),
KEY(1, 1, KEY_ENTER),
KEY(2, 1, KEY_UP),
KEY(0, 2, KEY_F3),
KEY(1, 2, KEY_RIGHT),
KEY(2, 2, KEY_F2),
0
};
static int innovator_keymap[] = {
KEY(0, 0, KEY_F1),
KEY(0, 3, KEY_DOWN),
KEY(1, 1, KEY_F2),
KEY(1, 2, KEY_RIGHT),
KEY(2, 0, KEY_F3),
KEY(2, 1, KEY_F4),
KEY(2, 2, KEY_UP),
KEY(3, 2, KEY_ENTER),
KEY(3, 3, KEY_LEFT),
0
};
static int osk_keymap[] = {
KEY(0, 0, KEY_F1),
KEY(0, 3, KEY_UP),
KEY(1, 1, KEY_LEFTCTRL),
KEY(1, 2, KEY_LEFT),
KEY(2, 0, KEY_SPACE),
KEY(2, 1, KEY_ESC),
KEY(2, 2, KEY_DOWN),
KEY(3, 2, KEY_ENTER),
KEY(3, 3, KEY_RIGHT),
0
};
static int *keymap;
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
/* disable keyboard interrupt and schedule for handling */
omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
tasklet_schedule(&kp_tasklet);
return IRQ_HANDLED;
}
static void omap_kp_timer(unsigned long data)
{
tasklet_schedule(&kp_tasklet);
}
static void omap_kp_scan_keypad(unsigned char *state)
{
int col = 0;
/* read the keypad status */
omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
for (col = 0; col < 8; col++) {
omap_writew(~(1 << col) & 0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
if (machine_is_omap_osk() || machine_is_omap_h2() || machine_is_omap_h3()) {
udelay(9);
} else {
udelay(2);
}
state[col] = ~omap_readw(OMAP_MPUIO_BASE + OMAP_MPUIO_KBR_LATCH) & 0xff;
}
omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
udelay(2);
}
static inline int omap_kp_find_key(int col, int row)
{
int i, key;
key = KEY(col, row, 0);
for (i = 0; keymap[i] != 0; i++)
if ((keymap[i] & 0xff000000) == key)
return keymap[i] & 0x00ffffff;
return -1;
}
static void omap_kp_tasklet(unsigned long data)
{
unsigned char new_state[8], changed, key_down = 0;
int col, row;
int spurious = 0;
/* check for any changes */
omap_kp_scan_keypad(new_state);
/* check for changes and print those */
for (col = 0; col < 8; col++) {
changed = new_state[col] ^ keypad_state[col];
key_down |= new_state[col];
if (changed == 0)
continue;
for (row = 0; row < 8; row++) {
int key;
if (!(changed & (1 << row)))
continue;
#ifdef NEW_BOARD_LEARNING_MODE
printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col, row, (new_state[col] & (1 << row)) ? "pressed" : "released");
#else
key = omap_kp_find_key(col, row);
if (key < 0) {
printk(KERN_WARNING "omap-keypad: Spurious key event %d-%d\n",
col, row);
/* We scan again after a couple of seconds */
spurious = 1;
continue;
}
input_report_key(&omap_kp_dev, key,
new_state[col] & (1 << row));
#endif
}
}
memcpy(keypad_state, new_state, sizeof(keypad_state));
if (key_down) {
int delay = HZ / 20;
/* some key is pressed - keep irq disabled and use timer
* to poll the keypad */
if (spurious)
delay = 2 * HZ;
mod_timer(&kp_timer, jiffies + delay);
} else {
/* enable interrupts */
omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
}
}
static int __init omap_kp_init(void)
{
int i;
printk(KERN_INFO "OMAP Keypad Driver\n");
/* Disable the interrupt for the MPUIO keyboard */
omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
if (machine_is_omap_h2() || machine_is_omap_h3()) {
keymap = h2_keymap;
set_bit(EV_REP, omap_kp_dev.evbit);
} else if (machine_is_omap_innovator()) {
keymap = innovator_keymap;
} else if (machine_is_omap_osk()) {
keymap = osk_keymap;
} else {
keymap = test_keymap;
}
init_timer(&kp_timer);
kp_timer.function = omap_kp_timer;
/* get the irq and init timer*/
tasklet_enable(&kp_tasklet);
if (request_irq(INT_KEYBOARD, omap_kp_interrupt, 0,
"omap-keypad", 0) < 0)
return -EINVAL;
/* setup input device */
set_bit(EV_KEY, omap_kp_dev.evbit);
for (i = 0; keymap[i] != 0; i++)
set_bit(keymap[i] & 0x00ffffff, omap_kp_dev.keybit);
omap_kp_dev.name = "omap-keypad";
input_register_device(&omap_kp_dev);
if (machine_is_omap_h2() || machine_is_omap_h3()) {
omap_cfg_reg(F18_1610_KBC0);
omap_cfg_reg(D20_1610_KBC1);
omap_cfg_reg(D19_1610_KBC2);
omap_cfg_reg(E18_1610_KBC3);
omap_cfg_reg(C21_1610_KBC4);
omap_cfg_reg(G18_1610_KBR0);
omap_cfg_reg(F19_1610_KBR1);
omap_cfg_reg(H14_1610_KBR2);
omap_cfg_reg(E20_1610_KBR3);
omap_cfg_reg(E19_1610_KBR4);
omap_cfg_reg(N19_1610_KBR5);
omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
}
/* scan current status and enable interrupt */
omap_kp_scan_keypad(keypad_state);
omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
return 0;
}
static void __exit omap_kp_exit(void)
{
/* disable keypad interrupt handling */
tasklet_disable(&kp_tasklet);
omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
free_irq(INT_KEYBOARD, 0);
del_timer_sync(&kp_timer);
/* unregister everything */
input_unregister_device(&omap_kp_dev);
}
module_init(omap_kp_init);
module_exit(omap_kp_exit);
MODULE_AUTHOR("Timo Ters");
MODULE_DESCRIPTION("OMAP Keypad Driver");
MODULE_LICENSE("GPL");
...@@ -96,3 +96,17 @@ config TOUCHSCREEN_HP600 ...@@ -96,3 +96,17 @@ config TOUCHSCREEN_HP600
module will be called hp680_ts_input. module will be called hp680_ts_input.
endif endif
config TOUCHSCREEN_OMAP
tristate "OMAP touchscreen input driver"
depends on INPUT && INPUT_TOUCHSCREEN
help
Say Y here if you have an OMAP based board with touchscreen
attached to it, e.g. OMAP Innovator, OSK, H2 or H3
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called omap_ts.
# #
# Makefile for the mouse drivers. # Makefile for the touchscreen input drivers.
# #
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
...@@ -11,3 +11,4 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o ...@@ -11,3 +11,4 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_OMAP) += omap/
#
# Makefile for the OMAP touchscreen input driver
#
obj-$(CONFIG_TOUCHSCREEN_OMAP) += omapts.o
objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H2) += ts_hx.o
objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_H3) += ts_hx.o
objs-$(CONFIG_ARCH_OMAP1510)$(CONFIG_MACH_OMAP_INNOVATOR) += ts_inn1510.o
objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_OSK) += ts_osk.o
omapts-objs := omap_ts.o $(objs-yy)
/*
* ads7846.h - header file for ADS7846 touchscreen controller
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ADS7846_H
#define __ADS7846_H
// ADS7846 Control Byte bit defines
#define ADS7846_S (1<<7)
#define ADS7846_ADDR_BIT 4
#define ADS7846_ADDR_MASK (0x7<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_X (0x5<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Y (0x1<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Z1 (0x3<<ADS7846_ADDR_BIT)
#define ADS7846_MEASURE_Z2 (0x4<<ADS7846_ADDR_BIT)
#define ADS7846_8BITS (1<<3)
#define ADS7846_12BITS 0
#define ADS7846_SER (1<<2)
#define ADS7846_DFR 0
#define ADS7846_PWR_BIT 0
#define ADS7846_PD 0
#define ADS7846_ADC_ON (0x1<<ADS7846_PWR_BIT)
#define ADS7846_REF_ON (0x2<<ADS7846_PWR_BIT)
#define ADS7846_REF_ADC_ON (0x3<<ADS7846_PWR_BIT)
#define MEASURE_12BIT_X \
(ADS7846_S | ADS7846_MEASURE_X | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Y \
(ADS7846_S | ADS7846_MEASURE_Y | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Z1 \
(ADS7846_S | ADS7846_MEASURE_Z1 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#define MEASURE_12BIT_Z2 \
(ADS7846_S | ADS7846_MEASURE_Z2 | ADS7846_12BITS | ADS7846_DFR | ADS7846_PD)
#endif /* __ADS7846_H */
/*
* input/touchscreen/omap/omap_ts.c
*
* touchscreen input device driver for various TI OMAP boards
* Copyright (c) 2002 MontaVista Software Inc.
* Copyright (c) 2004 Texas Instruments, Inc.
* Cleanup and modularization 2004 by Dirk Behme <dirk.behme@de.bosch.com>
*
* Assembled using driver code copyright the companies above.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* History:
* 12/12/2004 Srinath Modified and intergrated code for H2 and H3
*
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/device.h>
#include <asm/mach-types.h>
//#define DEBUG
#include "omap_ts.h"
#define OMAP_TS_NAME "omap_ts"
static struct ts_device *__initdata ts_devs[] = {
#if defined(CONFIG_MACH_OMAP_H2) || defined(CONFIG_MACH_OMAP_H3)
&hx_ts,
#endif
#ifdef CONFIG_MACH_OMAP_OSK
&osk_ts,
#endif
#if defined(CONFIG_MACH_OMAP_INNOVATOR) && defined(CONFIG_ARCH_OMAP1510)
&innovator1510_ts,
#endif
};
static struct omap_ts_t ts_omap;
static int omap_ts_read(void)
{
u16 data[4] = { 0, 0, 0, 0 };
ts_omap.dev->read(data);
input_report_abs(&(ts_omap.inputdevice), ABS_X, data[0]);
input_report_abs(&(ts_omap.inputdevice), ABS_Y, data[1]);
input_report_abs(&(ts_omap.inputdevice), ABS_PRESSURE, data[2]);
input_sync(&(ts_omap.inputdevice));
DEBUG_TS("omap_ts_read: read x=%d,y=%d,p=%d\n", data[0], data[1],
data[2]);
return 0;
}
static void omap_ts_timer(unsigned long data)
{
unsigned long flags;
spin_lock_irqsave(&ts_omap.lock, flags);
if (!ts_omap.dev->penup()) {
if (!ts_omap.touched) {
DEBUG_TS("omap_ts_timer: pen down\n");
input_report_key(&(ts_omap.inputdevice), BTN_TOUCH, 1);
}
ts_omap.touched = 1;
omap_ts_read();
ts_omap.ts_timer.expires = jiffies + HZ / 100;
add_timer(&(ts_omap.ts_timer));
} else {
if (ts_omap.touched) {
DEBUG_TS("omap_ts_timer: pen up\n");
ts_omap.touched = 0;
input_report_abs(&(ts_omap.inputdevice), ABS_X, 0);
input_report_abs(&(ts_omap.inputdevice), ABS_Y, 0);
input_report_abs(&(ts_omap.inputdevice), ABS_PRESSURE,
0);
input_sync(&(ts_omap.inputdevice));
input_report_key(&(ts_omap.inputdevice), BTN_TOUCH, 0);
}
if (!ts_omap.irq_enabled) {
ts_omap.irq_enabled = 1;
enable_irq(ts_omap.irq);
}
}
spin_unlock_irqrestore(&ts_omap.lock, flags);
}
static irqreturn_t omap_ts_handler(int irq, void *dev_id, struct pt_regs *regs)
{
spin_lock(&ts_omap.lock);
if (ts_omap.irq_enabled) {
ts_omap.irq_enabled = 0;
disable_irq(irq);
}
// restart acquire
ts_omap.ts_timer.expires = jiffies + HZ / 100;
add_timer(&(ts_omap.ts_timer));
spin_unlock(&ts_omap.lock);
return IRQ_HANDLED;
}
static int __init omap_ts_probe(struct device *dev)
{
int i;
int status = -ENODEV;
memset(&ts_omap, 0, sizeof(ts_omap));
spin_lock_init(&ts_omap.lock);
for (i = 0; i < ARRAY_SIZE(ts_devs); i++) {
if (!ts_devs[i] || !ts_devs[i]->probe)
continue;
status = ts_devs[i]->probe(&ts_omap);
if (status == 0) {
ts_omap.dev = ts_devs[i];
break;
}
}
if (status != 0)
return status;
// Init acquisition timer function
init_timer(&ts_omap.ts_timer);
ts_omap.ts_timer.function = omap_ts_timer;
/* request irq */
if (ts_omap.irq != -1) {
if (request_irq(ts_omap.irq, omap_ts_handler, 0,
OMAP_TS_NAME, &ts_omap)) {
printk(KERN_ERR
"omap_ts.c: Could not allocate touchscreen IRQ!\n");
ts_omap.irq = -1;
return -EINVAL;
}
ts_omap.irq_enabled = 1;
} else {
printk(KERN_ERR "omap_ts.c: No touchscreen IRQ assigned!\n");
return -EINVAL;
}
init_input_dev(&(ts_omap.inputdevice));
ts_omap.inputdevice.name = OMAP_TS_NAME;
ts_omap.inputdevice.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
ts_omap.inputdevice.keybit[LONG(BTN_TOUCH)] |= BIT(BTN_TOUCH);
ts_omap.inputdevice.absbit[0] =
BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
input_register_device(&(ts_omap.inputdevice));
ts_omap.dev->enable();
printk("OMAP touchscreen driver initialized\n");
return 0;
}
static int __exit omap_ts_remove(struct device *dev)
{
ts_omap.dev->disable();
input_unregister_device(&ts_omap.inputdevice);
if (ts_omap.irq != -1)
free_irq(ts_omap.irq, &ts_omap);
ts_omap.dev->remove();
return 0;
}
static int omap_ts_suspend(struct device *dev, pm_message_t mesg, u32 level)
{
if (level != SUSPEND_POWER_DOWN) {
return 0;
}
ts_omap.dev->disable();
return 0;
}
static int omap_ts_resume(struct device *dev, u32 level)
{
if (level != RESUME_POWER_ON) {
return 0;
}
ts_omap.dev->enable();
return 0;
}
static void omap_ts_device_release(struct device *dev)
{
/* Nothing */
}
static struct device_driver omap_ts_driver = {
.name = OMAP_TS_NAME,
.bus = &platform_bus_type,
.probe = omap_ts_probe,
.remove = __exit_p(omap_ts_remove),
.suspend = omap_ts_suspend,
.resume = omap_ts_resume,
};
static struct platform_device omap_ts_device = {
.name = OMAP_TS_NAME,
.id = -1,
.dev = {
.release = omap_ts_device_release,
},
};
static int __init omap_ts_init(void)
{
int ret;
ret = platform_device_register(&omap_ts_device);
if (ret != 0)
return -ENODEV;
ret = driver_register(&omap_ts_driver);
if (ret != 0) {
platform_device_unregister(&omap_ts_device);
return -ENODEV;
}
return 0;
}
static void __exit omap_ts_exit(void)
{
driver_unregister(&omap_ts_driver);
platform_device_unregister(&omap_ts_device);
}
module_init(omap_ts_init);
module_exit(omap_ts_exit);
MODULE_LICENSE("GPL");
/*
* omap_ts.h - header file for OMAP touchscreen support
*
* Copyright (c) 2002 MontaVista Software Inc.
* Copyright (c) 2004 Texas Instruments, Inc.
*
* Assembled using driver code copyright the companies above.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __OMAP_TS_H
#define __OMAP_TS_H
#ifdef DEBUG
#define DEBUG_TS(fmt...) printk(fmt)
#else
#define DEBUG_TS(fmt...) do { } while (0)
#endif
struct omap_ts_t;
struct ts_device {
int (*probe) (struct omap_ts_t *);
void (*read) (u16 *);
void (*enable) (void);
void (*disable) (void);
void (*remove) (void);
int (*penup) (void);
};
struct omap_ts_t{
struct input_dev inputdevice;
struct timer_list ts_timer; // Timer for triggering acquisitions
int touched;
int irq;
int irq_enabled;
struct ts_device *dev;
spinlock_t lock;
};
extern struct ts_device hx_ts;
extern struct ts_device osk_ts;
extern struct ts_device innovator1510_ts;
#endif /* __OMAP_TS_H */
/*
* input/touchscreen/omap/ts_hx.c
* touchscreen support for OMAP H3 and H2 boards
*
* Copyright (c) 2002 MontaVista Software Inc.
* Copyright (c) 2004 Texas Instruments, Inc.
*
* Assembled using driver code copyright the companies above.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* History:
* 9/12/2004 Srinath Modified and integrated H2 and H3 code
*
*/
#include <linux/input.h>
#include <linux/device.h>
#include <asm/mach-types.h>
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/hardware.h>
#include <asm/hardware/tsc2101.h>
#include "../drivers/ssi/omap-tsc2101.h"
#include "omap_ts.h"
#define H2_GPIO_NUM 4
#define H3_GPIO_NUM 48
#define OMAP_TSC2101_XRES 500
#define TOUCHSCREEN_DATA_REGISTERS_PAGE 0x0
#define TOUCHSCREEN_CONTROL_REGISTERS_PAGE 0x1
#define OMAP_TSC2101_READ_MAX 0x4
#define TSC2101_GETSTATUS(ret) (((ret) >> 11) & 0x1)
#define TSC2101_MASKVAL 0xFFF
#define TSC2101_PRESSUREVAL(x) ((x) << 12)
static int hx_ts_penup(void);
static int hx_ts_probe(struct omap_ts_t *ts);
static void hx_ts_read(u16 * data);
static void hx_ts_enable(void);
static void hx_ts_disable(void);
#ifdef MODULE
static void hx_ts_remove(void);
#endif
struct ts_device hx_ts = {
.probe = hx_ts_probe,
.read = hx_ts_read,
.enable = hx_ts_enable,
.disable = hx_ts_disable,
.remove = __exit_p(hx_ts_remove),
.penup = hx_ts_penup,
};
static int hx_ts_penup(void)
{
int ret = 0;
/* Read the status register */
ret = omap_tsc2101_read(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_STATUS);
/* Check for availability of data in status register */
ret = TSC2101_GETSTATUS(ret);
return !ret;
}
static int __init hx_ts_probe(struct omap_ts_t *ts)
{
unsigned gpio;
if (machine_is_omap_h2()) {
gpio = H2_GPIO_NUM;
omap_cfg_reg(P20_1610_GPIO4);
} else if (machine_is_omap_h3()) {
gpio = H3_GPIO_NUM;
omap_cfg_reg(W19_1610_GPIO48);
} else
return -ENODEV;
ts->irq = OMAP_GPIO_IRQ(gpio);
if (omap_request_gpio(gpio) != 0) {
printk(KERN_ERR "hX_ts_init.c: Could not reserve GPIO!\n");
return -EINVAL;
};
omap_set_gpio_direction(gpio, 1);
omap_set_gpio_edge_ctrl(gpio, OMAP_GPIO_FALLING_EDGE);
return 0;
}
static void hx_ts_read(u16 * values)
{
s32 t, p = 0;
int i;
/* Read X, Y, Z1 and Z2 */
omap_tsc2101_reads(TOUCHSCREEN_DATA_REGISTERS_PAGE, TSC2101_TS_X,
values, OMAP_TSC2101_READ_MAX);
for (i = 0; i < OMAP_TSC2101_READ_MAX; i++)
values[i] &= TSC2101_MASKVAL;
/* Calculate Pressure */
if (values[TSC2101_TS_Z1] != 0) {
t = ((OMAP_TSC2101_XRES * values[TSC2101_TS_X]) *
(values[TSC2101_TS_Z2] - values[TSC2101_TS_Z1]));
p = t / (u32) (TSC2101_PRESSUREVAL(values[TSC2101_TS_Z1]));
if (p < 0)
p = 0;
}
values[TSC2101_TS_Z1] = p;
}
static void hx_ts_enable(void)
{
int ret = omap_tsc2101_enable();
if (ret) {
printk(KERN_ERR "FAILED TO INITIALIZE TSC CODEC\n");
return;
}
/* PINTDAV is data available only */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_STATUS, TSC2101_DATA_AVAILABLE);
/* disable buffer mode */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_BUFFER_CTRL, TSC2101_BUFFERMODE_DISABLE);
/* use internal reference, 100 usec power-up delay,
* * power down between conversions, 1.25V internal reference */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_REF_CTRL, TSC2101_REF_POWERUP);
/* enable touch detection, 84usec precharge time, 32 usec sense time */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_CONFIG_CTRL, TSC2101_ENABLE_TOUCHDETECT);
/* 3 msec conversion delays */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_PROG_DELAY, TSC2101_PRG_DELAY);
/*
* TSC2101-controlled conversions
* 12-bit samples
* continuous X,Y,Z1,Z2 scan mode
* average (mean) 4 samples per coordinate
* 1 MHz internal conversion clock
* 500 usec panel voltage stabilization delay
*/
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_ADC_CTRL, TSC2101_ADC_CONTROL);
return;
}
static void hx_ts_disable(void)
{
/* stop conversions and power down */
omap_tsc2101_write(TOUCHSCREEN_CONTROL_REGISTERS_PAGE,
TSC2101_TS_ADC_CTRL, TSC2101_ADC_POWERDOWN);
omap_tsc2101_disable();
}
#ifdef MODULE
static void __exit hx_ts_remove(void)
{
if (machine_is_omap_h2())
omap_free_gpio(H2_GPIO_NUM);
else if (machine_is_omap_h3())
omap_free_gpio(H3_GPIO_NUM);
}
#endif
/*
* ts_inn1510.c - touchscreen support for OMAP1510 Innovator board
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* The touchscreen hardware on the Innovator consists of an FPGA
* register which is bit-banged to generate SPI-like transactions
* to an ADS7846 touch screen controller.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/input.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/mach-types.h>
#include <asm/arch/fpga.h>
#include "omap_ts.h"
#include "ads7846.h"
// The Touch Screen Register on Innovator FPGA
#define FPGA_TS_BCLK (1<<0)
#define FPGA_TS_BDIN (1<<1)
#define FPGA_TS_BCS (1<<2)
#define FPGA_TS_BBUSY (1<<3)
#define FPGA_TS_BOUT (1<<4)
#define FPGA_TS_BPENUP (1<<5)
#define X_PLATE_OHMS 419
#define Y_PLATE_OHMS 486
static int inn1510_ts_penup(void);
static int inn1510_ts_probe(struct omap_ts_t *ts);
static void inn1510_ts_read(u16 * data);
static void inn1510_ts_enable(void);
static void inn1510_ts_disable(void);
#ifdef MODULE
static void inn1510_ts_remove(void);
#endif
struct ts_device innovator1510_ts = {
.probe = inn1510_ts_probe,
.read = inn1510_ts_read,
.enable = inn1510_ts_enable,
.disable = inn1510_ts_disable,
.remove = __exit_p(inn1510_ts_remove),
.penup = inn1510_ts_penup,
};
static inline u8 fpga_ts_read(void)
{
return fpga_read(OMAP1510_FPGA_TOUCHSCREEN);
}
static inline void fpga_ts_write(u8 val)
{
fpga_write(val, OMAP1510_FPGA_TOUCHSCREEN);
}
static inline void fpga_ts_set_bits(u8 mask)
{
fpga_ts_write(fpga_ts_read() | mask);
}
static inline void fpga_ts_clear_bits(u8 mask)
{
fpga_ts_write(fpga_ts_read() & ~mask);
}
static inline void CS_H(void)
{
// EPLD inverts active low signals.
fpga_ts_clear_bits(FPGA_TS_BCS);
}
static inline void CS_L(void)
{
fpga_ts_set_bits(FPGA_TS_BCS);
}
static inline void SCLK_L(void)
{
fpga_ts_clear_bits(FPGA_TS_BCLK);
}
static inline void SCLK_H(void)
{
fpga_ts_set_bits(FPGA_TS_BCLK);
}
static inline void SDI_L(void)
{
fpga_ts_clear_bits(FPGA_TS_BDIN);
}
static inline void SDI_H(void)
{
fpga_ts_set_bits(FPGA_TS_BDIN);
}
static inline int BUSY(void)
{
return (((fpga_ts_read() & FPGA_TS_BBUSY) == 0) ? 1 : 0) ;
}
static inline u8 DOUT(void)
{
return ((fpga_ts_read() & FPGA_TS_BOUT) ? 1 : 0) ;
}
static u16 ads7846_do(u8 cmd)
{
int i;
u16 val=0;
SCLK_L() ;
SDI_L();
CS_L() ; // enable the chip select
// send the command to the ADS7846
for (i=0; i<8; i++ ) {
if (cmd & 0x80)
SDI_H();
else
SDI_L(); // prepare the data on line sdi OR din
SCLK_H() ; // clk in the data
cmd <<= 1 ;
SCLK_L() ;
}
SDI_L();
while (BUSY())
;
// now read returned data
for (i=0 ; i<16 ; i++ ) {
SCLK_L() ;
if (i < 12) {
val <<= 1 ;
val |= DOUT();
}
SCLK_H() ;
}
SCLK_L() ;
CS_H() ; // disable the chip select
return val;
}
static int inn1510_ts_penup(void)
{
return ((fpga_ts_read() & FPGA_TS_BPENUP) ? 0 : 1) ;
}
static int __init inn1510_ts_probe(struct omap_ts_t *ts)
{
if (!cpu_is_omap15xx() || !machine_is_omap_innovator())
return -ENODEV;
ts->irq = OMAP1510_INT_FPGA_TS;
return 0;
}
static void inn1510_ts_read(u16 *data)
{
unsigned int Rt = 0;
data[0] = ads7846_do(MEASURE_12BIT_X);
data[1] = ads7846_do(MEASURE_12BIT_Y);
data[2] = ads7846_do(MEASURE_12BIT_Z1);
data[3] = ads7846_do(MEASURE_12BIT_Z2);
// Calculate touch pressure resistance
if (data[2]) {
Rt = (X_PLATE_OHMS * (u32)data[0] *
((u32)data[3] - (u32)data[2])) / (u32)data[2];
Rt = (Rt + 2048) >> 12; // round up to nearest ohm
}
data[2] = Rt;
}
static void inn1510_ts_enable(void)
{
}
static void inn1510_ts_disable(void)
{
}
#ifdef MODULE
static void __exit inn1510_ts_remove(void)
{
/* Nothing to do here */
}
#endif
/*
* ts_osk.c - touchscreen support for OMAP OSK board
*
* Copyright 2002 MontaVista Software Inc.
* Author: MontaVista Software, Inc.
* stevel@mvista.com or source@mvista.com
*
* The touchscreen hardware on the OSK uses OMAP5912 uWire interface,
* GPIO4 (/PENIRQ) and GPIO6 (BUSY) to connect to an ADS7846
* touch screen controller. GPIO6 doesn't seem to be necessary here.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/input.h>
#include <linux/device.h>
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
#include <asm/mach-types.h>
#include "../drivers/ssi/omap-uwire.h"
#include "omap_ts.h"
#include "ads7846.h"
// /PENIRQ on GPIO4 on OSK
#define PEN_IRQ OMAP_GPIO_IRQ(4)
// ADS7846 is on OSK uWire CS 0
#define ADS7846_UWIRE_CS 0
#define UWIRE_LEAVE_CS 1
#define X_PLATE_OHMS 419
#define Y_PLATE_OHMS 486
static int osk_ts_penup(void);
static int osk_ts_probe(struct omap_ts_t *ts);
static void osk_ts_read(u16 * data);
static void osk_ts_enable(void);
static void osk_ts_disable(void);
#ifdef MODULE
static void osk_ts_remove(void);
#endif
struct ts_device osk_ts = {
.probe = osk_ts_probe,
.read = osk_ts_read,
.enable = osk_ts_enable,
.disable = osk_ts_disable,
.remove = __exit_p(osk_ts_remove),
.penup = osk_ts_penup,
};
static u16 ads7846_do(u8 cmd)
{
u16 val = 0;
// send the command to the ADS7846, leave CS active after this
omap_uwire_data_transfer(ADS7846_UWIRE_CS, cmd, 8, 0, NULL, UWIRE_LEAVE_CS);
// now read returned data
omap_uwire_data_transfer(ADS7846_UWIRE_CS, 0, 0, 16, &val, !UWIRE_LEAVE_CS);
return val;
}
static int osk_ts_penup(void)
{
return (omap_get_gpio_datain(4));
}
static int __init osk_ts_probe(struct omap_ts_t *ts)
{
if (!machine_is_omap_osk())
return -ENODEV;
/* Configure GPIO4 (pin M17 ZDY) as /PENIRQ interrupt input */
omap_cfg_reg(P20_1610_GPIO4);
omap_request_gpio(4);
omap_set_gpio_direction(4, 1);
omap_set_gpio_edge_ctrl(4, OMAP_GPIO_FALLING_EDGE);
ts->irq = PEN_IRQ;
/* Configure uWire interface. ADS7846 is on CS0 */
omap_uwire_configure_mode(ADS7846_UWIRE_CS, UWIRE_READ_RISING_EDGE |
UWIRE_WRITE_RISING_EDGE |
UWIRE_CS_ACTIVE_LOW |
UWIRE_FREQ_DIV_2);
return 0;
}
static void osk_ts_read(u16 *data)
{
unsigned int Rt = 0;
data[0] = ads7846_do(MEASURE_12BIT_X);
data[1] = ads7846_do(MEASURE_12BIT_Y);
data[2] = ads7846_do(MEASURE_12BIT_Z1);
data[3] = ads7846_do(MEASURE_12BIT_Z2);
// Calculate touch pressure resistance
if (data[2]) {
Rt = (X_PLATE_OHMS * (u32)data[0] *
((u32)data[3] - (u32)data[2])) / (u32)data[2];
Rt = (Rt + 2048) >> 12; // round up to nearest ohm
}
/*
* Raw OSK touchscreen data values are between ~4000 and
* ~60000. This seems to be to large for calibration
* systems (e.g. tslib). Make the values smaller.
*/
data[0] = data[0] >> 4;
data[1] = data[1] >> 4;
data[2] = Rt;
}
static void osk_ts_enable(void)
{
}
static void osk_ts_disable(void)
{
}
#ifdef MODULE
static void __exit osk_ts_remove(void)
{
omap_free_gpio(4);
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment