Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input subsystem updates from Dmitry Torokhov: "- we finally merged driver for USB version of Synaptics touchpads (I guess most commonly found in IBM/Lenovo keyboard/touchpad combo); - a bunch of new drivers for embedded platforms (Cypress touchscreens, DA9052 OnKey, MAX8997-haptic, Ilitek ILI210x touchscreens, TI touchscreen); - input core allows clients to specify desired clock source for timestamps on input events (EVIOCSCLOCKID ioctl); - input core allows querying state of all MT slots for given event code via EVIOCGMTSLOTS ioctl; - various driver fixes and improvements." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (45 commits) Input: ili210x - add support for Ilitek ILI210x based touchscreens Input: altera_ps2 - use of_match_ptr() Input: synaptics_usb - switch to module_usb_driver() Input: convert I2C drivers to use module_i2c_driver() Input: convert SPI drivers to use module_spi_driver() Input: omap4-keypad - move platform_data to <linux/platform_data> Input: kxtj9 - who_am_i check value and initial data rate fixes Input: add driver support for MAX8997-haptic Input: tegra-kbc - revise device tree support Input: of_keymap - add device tree bindings for simple key matrices Input: wacom - fix physical size calculation for 3rd-gen Bamboo Input: twl4030-vibra - really switch from #if to #ifdef Input: hp680_ts_input - ensure arguments to request_irq and free_irq are compatible Input: max8925_onkey - avoid accessing input device too early Input: max8925_onkey - allow to be used as a wakeup source Input: atmel-wm97xx - convert to dev_pm_ops Input: atmel-wm97xx - set driver owner Input: add cyttsp touchscreen maintainer entry Input: cyttsp - remove useless checks in cyttsp_probe() Input: usbtouchscreen - add support for Data Modul EasyTouch TP 72037 ...
This commit is contained in:
commit
7bfe0e66d5
101 changed files with 4091 additions and 706 deletions
19
Documentation/devicetree/bindings/input/matrix-keymap.txt
Normal file
19
Documentation/devicetree/bindings/input/matrix-keymap.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
A simple common binding for matrix-connected key boards. Currently targeted at
|
||||
defining the keys in the scope of linux key codes since that is a stable and
|
||||
standardized interface at this time.
|
||||
|
||||
Required properties:
|
||||
- linux,keymap: an array of packed 1-cell entries containing the equivalent
|
||||
of row, column and linux key-code. The 32-bit big endian cell is packed
|
||||
as:
|
||||
row << 24 | column << 16 | key-code
|
||||
|
||||
Optional properties:
|
||||
Some users of this binding might choose to specify secondary keymaps for
|
||||
cases where there is a modifier key such as a Fn key. Proposed names
|
||||
for said properties are "linux,fn-keymap" or with another descriptive
|
||||
word for the modifier other from "Fn".
|
||||
|
||||
Example:
|
||||
linux,keymap = < 0x00030012
|
||||
0x0102003a >;
|
|
@ -3,16 +3,21 @@
|
|||
Required properties:
|
||||
- compatible: "nvidia,tegra20-kbc"
|
||||
|
||||
Optional properties:
|
||||
- debounce-delay: delay in milliseconds per row scan for debouncing
|
||||
- repeat-delay: delay in milliseconds before repeat starts
|
||||
- ghost-filter: enable ghost filtering for this device
|
||||
- wakeup-source: configure keyboard as a wakeup source for suspend/resume
|
||||
Optional properties, in addition to those specified by the shared
|
||||
matrix-keyboard bindings:
|
||||
|
||||
- linux,fn-keymap: a second keymap, same specification as the
|
||||
matrix-keyboard-controller spec but to be used when the KEY_FN modifier
|
||||
key is pressed.
|
||||
- nvidia,debounce-delay-ms: delay in milliseconds per row scan for debouncing
|
||||
- nvidia,repeat-delay-ms: delay in milliseconds before repeat starts
|
||||
- nvidia,ghost-filter: enable ghost filtering for this device
|
||||
- nvidia,wakeup-source: configure keyboard as a wakeup source for suspend/resume
|
||||
|
||||
Example:
|
||||
|
||||
keyboard: keyboard {
|
||||
compatible = "nvidia,tegra20-kbc";
|
||||
reg = <0x7000e200 0x100>;
|
||||
ghost-filter;
|
||||
nvidia,ghost-filter;
|
||||
};
|
||||
|
|
|
@ -2109,6 +2109,13 @@ W: http://www.cyclades.com/
|
|||
S: Orphan
|
||||
F: drivers/net/wan/pc300*
|
||||
|
||||
CYTTSP TOUCHSCREEN DRIVER
|
||||
M: Javier Martinez Canillas <javier@dowhile0.org>
|
||||
L: linux-input@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/input/touchscreen/cyttsp*
|
||||
F: include/linux/input/cyttsp.h
|
||||
|
||||
DAMA SLAVE for AX.25
|
||||
M: Joerg Reuter <jreuter@yaina.de>
|
||||
W: http://yaina.de/jreuter/
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/leds_pwm.h>
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/irqs.h>
|
||||
|
|
|
@ -24,20 +24,21 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
|
||||
#define KBC_MAX_GPIO 24
|
||||
#define KBC_MAX_KPENT 8
|
||||
#else
|
||||
#define KBC_MAX_GPIO 20
|
||||
#define KBC_MAX_KPENT 7
|
||||
#endif
|
||||
|
||||
#define KBC_MAX_ROW 16
|
||||
#define KBC_MAX_COL 8
|
||||
#define KBC_MAX_KEY (KBC_MAX_ROW * KBC_MAX_COL)
|
||||
|
||||
enum tegra_pin_type {
|
||||
PIN_CFG_IGNORE,
|
||||
PIN_CFG_COL,
|
||||
PIN_CFG_ROW,
|
||||
};
|
||||
|
||||
struct tegra_kbc_pin_cfg {
|
||||
bool is_row;
|
||||
enum tegra_pin_type type;
|
||||
unsigned char num;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,15 +1,6 @@
|
|||
#ifndef ARCH_ARM_PLAT_OMAP4_KEYPAD_H
|
||||
#define ARCH_ARM_PLAT_OMAP4_KEYPAD_H
|
||||
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
struct omap4_keypad_platform_data {
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
|
||||
u8 rows;
|
||||
u8 cols;
|
||||
};
|
||||
|
||||
extern int omap4_keyboard_init(struct omap4_keypad_platform_data *,
|
||||
struct omap_board_data *);
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DECLARE_KEYMAP(_name) \
|
||||
#define DECLARE_9x9_KEYMAP(_name) \
|
||||
int _name[] = { \
|
||||
KEY(0, 0, KEY_ESC), \
|
||||
KEY(0, 1, KEY_1), \
|
||||
|
@ -62,24 +62,6 @@ int _name[] = { \
|
|||
KEY(4, 6, KEY_Z), \
|
||||
KEY(4, 7, KEY_X), \
|
||||
KEY(4, 8, KEY_C), \
|
||||
KEY(4, 0, KEY_L), \
|
||||
KEY(4, 1, KEY_SEMICOLON), \
|
||||
KEY(4, 2, KEY_APOSTROPHE), \
|
||||
KEY(4, 3, KEY_GRAVE), \
|
||||
KEY(4, 4, KEY_LEFTSHIFT), \
|
||||
KEY(4, 5, KEY_BACKSLASH), \
|
||||
KEY(4, 6, KEY_Z), \
|
||||
KEY(4, 7, KEY_X), \
|
||||
KEY(4, 8, KEY_C), \
|
||||
KEY(4, 0, KEY_L), \
|
||||
KEY(4, 1, KEY_SEMICOLON), \
|
||||
KEY(4, 2, KEY_APOSTROPHE), \
|
||||
KEY(4, 3, KEY_GRAVE), \
|
||||
KEY(4, 4, KEY_LEFTSHIFT), \
|
||||
KEY(4, 5, KEY_BACKSLASH), \
|
||||
KEY(4, 6, KEY_Z), \
|
||||
KEY(4, 7, KEY_X), \
|
||||
KEY(4, 8, KEY_C), \
|
||||
KEY(5, 0, KEY_V), \
|
||||
KEY(5, 1, KEY_B), \
|
||||
KEY(5, 2, KEY_N), \
|
||||
|
@ -118,10 +100,55 @@ int _name[] = { \
|
|||
KEY(8, 8, KEY_KP0), \
|
||||
}
|
||||
|
||||
#define DECLARE_6x6_KEYMAP(_name) \
|
||||
int _name[] = { \
|
||||
KEY(0, 0, KEY_RESERVED), \
|
||||
KEY(0, 1, KEY_1), \
|
||||
KEY(0, 2, KEY_2), \
|
||||
KEY(0, 3, KEY_3), \
|
||||
KEY(0, 4, KEY_4), \
|
||||
KEY(0, 5, KEY_5), \
|
||||
KEY(1, 0, KEY_Q), \
|
||||
KEY(1, 1, KEY_W), \
|
||||
KEY(1, 2, KEY_E), \
|
||||
KEY(1, 3, KEY_R), \
|
||||
KEY(1, 4, KEY_T), \
|
||||
KEY(1, 5, KEY_Y), \
|
||||
KEY(2, 0, KEY_D), \
|
||||
KEY(2, 1, KEY_F), \
|
||||
KEY(2, 2, KEY_G), \
|
||||
KEY(2, 3, KEY_H), \
|
||||
KEY(2, 4, KEY_J), \
|
||||
KEY(2, 5, KEY_K), \
|
||||
KEY(3, 0, KEY_B), \
|
||||
KEY(3, 1, KEY_N), \
|
||||
KEY(3, 2, KEY_M), \
|
||||
KEY(3, 3, KEY_COMMA), \
|
||||
KEY(3, 4, KEY_DOT), \
|
||||
KEY(3, 5, KEY_SLASH), \
|
||||
KEY(4, 0, KEY_F6), \
|
||||
KEY(4, 1, KEY_F7), \
|
||||
KEY(4, 2, KEY_F8), \
|
||||
KEY(4, 3, KEY_F9), \
|
||||
KEY(4, 4, KEY_F10), \
|
||||
KEY(4, 5, KEY_NUMLOCK), \
|
||||
KEY(5, 0, KEY_KP2), \
|
||||
KEY(5, 1, KEY_KP3), \
|
||||
KEY(5, 2, KEY_KP0), \
|
||||
KEY(5, 3, KEY_KPDOT), \
|
||||
KEY(5, 4, KEY_RO), \
|
||||
KEY(5, 5, KEY_ZENKAKUHANKAKU), \
|
||||
}
|
||||
|
||||
#define KEYPAD_9x9 0
|
||||
#define KEYPAD_6x6 1
|
||||
#define KEYPAD_2x2 2
|
||||
|
||||
/**
|
||||
* struct kbd_platform_data - spear keyboard platform data
|
||||
* keymap: pointer to keymap data (table and size)
|
||||
* rep: enables key autorepeat
|
||||
* mode: choose keyboard support(9x9, 6x6, 2x2)
|
||||
*
|
||||
* This structure is supposed to be used by platform code to supply
|
||||
* keymaps to drivers that implement keyboards.
|
||||
|
@ -129,6 +156,7 @@ int _name[] = { \
|
|||
struct kbd_platform_data {
|
||||
const struct matrix_keymap_data *keymap;
|
||||
bool rep;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
/* This function is used to set platform data field of pdev->dev */
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/rtc.h>
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/rtc.h>
|
||||
|
@ -329,3 +330,15 @@ static int q40_set_rtc_pll(struct rtc_pll_info *pll)
|
|||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static __init int q40_add_kbd_device(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
||||
pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(q40_add_kbd_device);
|
||||
|
|
|
@ -1935,6 +1935,16 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
|
||||
#if defined(CONFIG_MOUSE_SYNAPTICS_USB) || defined(CONFIG_MOUSE_SYNAPTICS_USB_MODULE)
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
|
||||
#endif
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
|
||||
|
|
|
@ -677,6 +677,17 @@
|
|||
#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
|
||||
#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
|
||||
|
||||
#define USB_VENDOR_ID_SYNAPTICS 0x06cb
|
||||
#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001
|
||||
#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002
|
||||
#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003
|
||||
#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006
|
||||
#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007
|
||||
#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008
|
||||
#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009
|
||||
#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010
|
||||
#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013
|
||||
|
||||
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
|
||||
|
||||
#define USB_VENDOR_ID_TIVO 0x150a
|
||||
|
|
|
@ -25,6 +25,10 @@ config INPUT
|
|||
|
||||
if INPUT
|
||||
|
||||
config INPUT_OF_MATRIX_KEYMAP
|
||||
depends on USE_OF
|
||||
bool
|
||||
|
||||
config INPUT_FF_MEMLESS
|
||||
tristate "Support for memoryless force-feedback devices"
|
||||
help
|
||||
|
|
|
@ -24,3 +24,4 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
|
|||
obj-$(CONFIG_INPUT_MISC) += misc/
|
||||
|
||||
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
|
||||
obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/device.h>
|
||||
#include "input-compat.h"
|
||||
|
@ -46,6 +46,7 @@ struct evdev_client {
|
|||
struct fasync_struct *fasync;
|
||||
struct evdev *evdev;
|
||||
struct list_head node;
|
||||
int clkid;
|
||||
unsigned int bufsize;
|
||||
struct input_event buffer[];
|
||||
};
|
||||
|
@ -54,8 +55,12 @@ static struct evdev *evdev_table[EVDEV_MINORS];
|
|||
static DEFINE_MUTEX(evdev_table_mutex);
|
||||
|
||||
static void evdev_pass_event(struct evdev_client *client,
|
||||
struct input_event *event)
|
||||
struct input_event *event,
|
||||
ktime_t mono, ktime_t real)
|
||||
{
|
||||
event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
|
||||
mono : real);
|
||||
|
||||
/* Interrupts are disabled, just acquire the lock. */
|
||||
spin_lock(&client->buffer_lock);
|
||||
|
||||
|
@ -94,8 +99,11 @@ static void evdev_event(struct input_handle *handle,
|
|||
struct evdev *evdev = handle->private;
|
||||
struct evdev_client *client;
|
||||
struct input_event event;
|
||||
ktime_t time_mono, time_real;
|
||||
|
||||
time_mono = ktime_get();
|
||||
time_real = ktime_sub(time_mono, ktime_get_monotonic_offset());
|
||||
|
||||
do_gettimeofday(&event.time);
|
||||
event.type = type;
|
||||
event.code = code;
|
||||
event.value = value;
|
||||
|
@ -103,11 +111,12 @@ static void evdev_event(struct input_handle *handle,
|
|||
rcu_read_lock();
|
||||
|
||||
client = rcu_dereference(evdev->grab);
|
||||
|
||||
if (client)
|
||||
evdev_pass_event(client, &event);
|
||||
evdev_pass_event(client, &event, time_mono, time_real);
|
||||
else
|
||||
list_for_each_entry_rcu(client, &evdev->client_list, node)
|
||||
evdev_pass_event(client, &event);
|
||||
evdev_pass_event(client, &event, time_mono, time_real);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -623,6 +632,28 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
|
|||
return input_set_keycode(dev, &ke);
|
||||
}
|
||||
|
||||
static int evdev_handle_mt_request(struct input_dev *dev,
|
||||
unsigned int size,
|
||||
int __user *ip)
|
||||
{
|
||||
const struct input_mt_slot *mt = dev->mt;
|
||||
unsigned int code;
|
||||
int max_slots;
|
||||
int i;
|
||||
|
||||
if (get_user(code, &ip[0]))
|
||||
return -EFAULT;
|
||||
if (!input_is_mt_value(code))
|
||||
return -EINVAL;
|
||||
|
||||
max_slots = (size - sizeof(__u32)) / sizeof(__s32);
|
||||
for (i = 0; i < dev->mtsize && i < max_slots; i++)
|
||||
if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i]))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long evdev_do_ioctl(struct file *file, unsigned int cmd,
|
||||
void __user *p, int compat_mode)
|
||||
{
|
||||
|
@ -685,6 +716,14 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
else
|
||||
return evdev_ungrab(evdev, client);
|
||||
|
||||
case EVIOCSCLOCKID:
|
||||
if (copy_from_user(&i, p, sizeof(unsigned int)))
|
||||
return -EFAULT;
|
||||
if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)
|
||||
return -EINVAL;
|
||||
client->clkid = i;
|
||||
return 0;
|
||||
|
||||
case EVIOCGKEYCODE:
|
||||
return evdev_handle_get_keycode(dev, p);
|
||||
|
||||
|
@ -708,6 +747,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
|
|||
return bits_to_user(dev->propbit, INPUT_PROP_MAX,
|
||||
size, p, compat_mode);
|
||||
|
||||
case EVIOCGMTSLOTS(0):
|
||||
return evdev_handle_mt_request(dev, size, ip);
|
||||
|
||||
case EVIOCGKEY(0):
|
||||
return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ static int input_handle_abs_event(struct input_dev *dev,
|
|||
return INPUT_IGNORE_EVENT;
|
||||
}
|
||||
|
||||
is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST;
|
||||
is_mt_event = input_is_mt_value(code);
|
||||
|
||||
if (!is_mt_event) {
|
||||
pold = &dev->absinfo[code].value;
|
||||
|
|
|
@ -355,14 +355,4 @@ static struct i2c_driver as5011_driver = {
|
|||
.id_table = as5011_id,
|
||||
};
|
||||
|
||||
static int __init as5011_init(void)
|
||||
{
|
||||
return i2c_add_driver(&as5011_driver);
|
||||
}
|
||||
module_init(as5011_init);
|
||||
|
||||
static void __exit as5011_exit(void)
|
||||
{
|
||||
i2c_del_driver(&as5011_driver);
|
||||
}
|
||||
module_exit(as5011_exit);
|
||||
module_i2c_driver(as5011_driver);
|
||||
|
|
|
@ -394,6 +394,7 @@ config KEYBOARD_NOMADIK
|
|||
config KEYBOARD_TEGRA
|
||||
tristate "NVIDIA Tegra internal matrix keyboard controller support"
|
||||
depends on ARCH_TEGRA
|
||||
select INPUT_OF_MATRIX_KEYMAP if USE_OF
|
||||
help
|
||||
Say Y here if you want to use a matrix keyboard connected directly
|
||||
to the internal keyboard controller on Tegra SoCs.
|
||||
|
@ -512,7 +513,6 @@ config KEYBOARD_OMAP
|
|||
|
||||
config KEYBOARD_OMAP4
|
||||
tristate "TI OMAP4 keypad support"
|
||||
depends on ARCH_OMAP4
|
||||
help
|
||||
Say Y here if you want to use the OMAP4 keypad.
|
||||
|
||||
|
|
|
@ -653,17 +653,7 @@ static struct i2c_driver adp5588_driver = {
|
|||
.id_table = adp5588_id,
|
||||
};
|
||||
|
||||
static int __init adp5588_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adp5588_driver);
|
||||
}
|
||||
module_init(adp5588_init);
|
||||
|
||||
static void __exit adp5588_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adp5588_driver);
|
||||
}
|
||||
module_exit(adp5588_exit);
|
||||
module_i2c_driver(adp5588_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
|
|
|
@ -1108,17 +1108,7 @@ static struct i2c_driver adp5589_driver = {
|
|||
.id_table = adp5589_id,
|
||||
};
|
||||
|
||||
static int __init adp5589_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adp5589_driver);
|
||||
}
|
||||
module_init(adp5589_init);
|
||||
|
||||
static void __exit adp5589_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adp5589_driver);
|
||||
}
|
||||
module_exit(adp5589_exit);
|
||||
module_i2c_driver(adp5589_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
|
|
|
@ -851,17 +851,7 @@ static struct i2c_driver lm8323_i2c_driver = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm8323_id);
|
||||
|
||||
static int __init lm8323_init(void)
|
||||
{
|
||||
return i2c_add_driver(&lm8323_i2c_driver);
|
||||
}
|
||||
module_init(lm8323_init);
|
||||
|
||||
static void __exit lm8323_exit(void)
|
||||
{
|
||||
i2c_del_driver(&lm8323_i2c_driver);
|
||||
}
|
||||
module_exit(lm8323_exit);
|
||||
module_i2c_driver(lm8323_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>");
|
||||
MODULE_AUTHOR("Daniel Stone");
|
||||
|
|
|
@ -316,17 +316,7 @@ static struct i2c_driver max7359_i2c_driver = {
|
|||
.id_table = max7359_ids,
|
||||
};
|
||||
|
||||
static int __init max7359_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max7359_i2c_driver);
|
||||
}
|
||||
module_init(max7359_init);
|
||||
|
||||
static void __exit max7359_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max7359_i2c_driver);
|
||||
}
|
||||
module_exit(max7359_exit);
|
||||
module_i2c_driver(max7359_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver");
|
||||
|
|
|
@ -274,18 +274,7 @@ static struct i2c_driver mcs_touchkey_driver = {
|
|||
.id_table = mcs_touchkey_id,
|
||||
};
|
||||
|
||||
static int __init mcs_touchkey_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mcs_touchkey_driver);
|
||||
}
|
||||
|
||||
static void __exit mcs_touchkey_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mcs_touchkey_driver);
|
||||
}
|
||||
|
||||
module_init(mcs_touchkey_init);
|
||||
module_exit(mcs_touchkey_exit);
|
||||
module_i2c_driver(mcs_touchkey_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
|
|
|
@ -330,17 +330,7 @@ static struct i2c_driver mpr_touchkey_driver = {
|
|||
.remove = __devexit_p(mpr_touchkey_remove),
|
||||
};
|
||||
|
||||
static int __init mpr_touchkey_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mpr_touchkey_driver);
|
||||
}
|
||||
module_init(mpr_touchkey_init);
|
||||
|
||||
static void __exit mpr_touchkey_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mpr_touchkey_driver);
|
||||
}
|
||||
module_exit(mpr_touchkey_exit);
|
||||
module_i2c_driver(mpr_touchkey_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
|
||||
|
|
|
@ -88,7 +88,7 @@ static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
|
|||
*
|
||||
* Enable Multi key press detection, auto scan mode
|
||||
*/
|
||||
static int __devinit ske_keypad_chip_init(struct ske_keypad *keypad)
|
||||
static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
|
||||
{
|
||||
u32 value;
|
||||
int timeout = 50;
|
||||
|
@ -198,7 +198,7 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit ske_keypad_probe(struct platform_device *pdev)
|
||||
static int __init ske_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct ske_keypad_platform_data *plat = pdev->dev.platform_data;
|
||||
struct ske_keypad *keypad;
|
||||
|
@ -344,7 +344,7 @@ static int __devexit ske_keypad_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ske_keypad_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
@ -372,22 +372,17 @@ static int ske_keypad_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ske_keypad_dev_pm_ops = {
|
||||
.suspend = ske_keypad_suspend,
|
||||
.resume = ske_keypad_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops,
|
||||
ske_keypad_suspend, ske_keypad_resume);
|
||||
|
||||
static struct platform_driver ske_keypad_driver = {
|
||||
.driver = {
|
||||
.name = "nmk-ske-keypad",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &ske_keypad_dev_pm_ops,
|
||||
#endif
|
||||
},
|
||||
.probe = ske_keypad_probe,
|
||||
.remove = __devexit_p(ske_keypad_remove),
|
||||
};
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <plat/omap4-keypad.h>
|
||||
#include <linux/platform_data/omap4-keypad.h>
|
||||
|
||||
/* OMAP4 registers */
|
||||
#define OMAP4_KBD_REVISION 0x00
|
||||
|
|
|
@ -258,17 +258,7 @@ static struct i2c_driver qt1070_driver = {
|
|||
.remove = __devexit_p(qt1070_remove),
|
||||
};
|
||||
|
||||
static int __init qt1070_init(void)
|
||||
{
|
||||
return i2c_add_driver(&qt1070_driver);
|
||||
}
|
||||
module_init(qt1070_init);
|
||||
|
||||
static void __exit qt1070_exit(void)
|
||||
{
|
||||
i2c_del_driver(&qt1070_driver);
|
||||
}
|
||||
module_exit(qt1070_exit);
|
||||
module_i2c_driver(qt1070_driver);
|
||||
|
||||
MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
|
||||
MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor");
|
||||
|
|
|
@ -379,17 +379,7 @@ static struct i2c_driver qt2160_driver = {
|
|||
.remove = __devexit_p(qt2160_remove),
|
||||
};
|
||||
|
||||
static int __init qt2160_init(void)
|
||||
{
|
||||
return i2c_add_driver(&qt2160_driver);
|
||||
}
|
||||
module_init(qt2160_init);
|
||||
|
||||
static void __exit qt2160_cleanup(void)
|
||||
{
|
||||
i2c_del_driver(&qt2160_driver);
|
||||
}
|
||||
module_exit(qt2160_cleanup);
|
||||
module_i2c_driver(qt2160_driver);
|
||||
|
||||
MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
|
||||
|
|
|
@ -175,7 +175,7 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id)
|
|||
|
||||
} while (key_down && !keypad->stopped);
|
||||
|
||||
pm_runtime_put_sync(&keypad->pdev->dev);
|
||||
pm_runtime_put(&keypad->pdev->dev);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ static void samsung_keypad_start(struct samsung_keypad *keypad)
|
|||
/* KEYIFCOL reg clear. */
|
||||
writel(0, keypad->base + SAMSUNG_KEYIFCOL);
|
||||
|
||||
pm_runtime_put_sync(&keypad->pdev->dev);
|
||||
pm_runtime_put(&keypad->pdev->dev);
|
||||
}
|
||||
|
||||
static void samsung_keypad_stop(struct samsung_keypad *keypad)
|
||||
|
@ -229,7 +229,7 @@ static void samsung_keypad_stop(struct samsung_keypad *keypad)
|
|||
*/
|
||||
enable_irq(keypad->irq);
|
||||
|
||||
pm_runtime_put_sync(&keypad->pdev->dev);
|
||||
pm_runtime_put(&keypad->pdev->dev);
|
||||
}
|
||||
|
||||
static int samsung_keypad_open(struct input_dev *input_dev)
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define ROW_MASK 0xF0
|
||||
#define COLUMN_MASK 0x0F
|
||||
#define ROW_SHIFT 4
|
||||
#define KEY_MATRIX_SHIFT 6
|
||||
|
||||
struct spear_kbd {
|
||||
struct input_dev *input;
|
||||
|
@ -57,6 +58,7 @@ struct spear_kbd {
|
|||
void __iomem *io_base;
|
||||
struct clk *clk;
|
||||
unsigned int irq;
|
||||
unsigned int mode;
|
||||
unsigned short last_key;
|
||||
unsigned short keycodes[256];
|
||||
};
|
||||
|
@ -106,7 +108,8 @@ static int spear_kbd_open(struct input_dev *dev)
|
|||
return error;
|
||||
|
||||
/* program keyboard */
|
||||
val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK;
|
||||
val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
|
||||
(kbd->mode << KEY_MATRIX_SHIFT);
|
||||
writew(val, kbd->io_base + MODE_REG);
|
||||
writeb(1, kbd->io_base + STATUS_REG);
|
||||
|
||||
|
@ -176,6 +179,8 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
|
|||
|
||||
kbd->input = input_dev;
|
||||
kbd->irq = irq;
|
||||
kbd->mode = pdata->mode;
|
||||
|
||||
kbd->res = request_mem_region(res->start, resource_size(res),
|
||||
pdev->name);
|
||||
if (!kbd->res) {
|
||||
|
@ -308,22 +313,17 @@ static int spear_kbd_resume(struct device *dev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops spear_kbd_pm_ops = {
|
||||
.suspend = spear_kbd_suspend,
|
||||
.resume = spear_kbd_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
|
||||
|
||||
static struct platform_driver spear_kbd_driver = {
|
||||
.probe = spear_kbd_probe,
|
||||
.remove = __devexit_p(spear_kbd_remove),
|
||||
.driver = {
|
||||
.name = "keyboard",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_PM
|
||||
.pm = &spear_kbd_pm_ops,
|
||||
#endif
|
||||
},
|
||||
};
|
||||
module_platform_driver(spear_kbd_driver);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define KBC_FIFO_TH_CNT_SHIFT(cnt) (cnt << 14)
|
||||
#define KBC_DEBOUNCE_CNT_SHIFT(cnt) (cnt << 4)
|
||||
#define KBC_CONTROL_FIFO_CNT_INT_EN (1 << 3)
|
||||
#define KBC_CONTROL_KEYPRESS_INT_EN (1 << 1)
|
||||
#define KBC_CONTROL_KBC_EN (1 << 0)
|
||||
|
||||
/* KBC Interrupt Register */
|
||||
|
@ -356,6 +357,18 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
|
|||
writel(val, kbc->mmio + KBC_CONTROL_0);
|
||||
}
|
||||
|
||||
static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl(kbc->mmio + KBC_CONTROL_0);
|
||||
if (enable)
|
||||
val |= KBC_CONTROL_KEYPRESS_INT_EN;
|
||||
else
|
||||
val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
|
||||
writel(val, kbc->mmio + KBC_CONTROL_0);
|
||||
}
|
||||
|
||||
static void tegra_kbc_keypress_timer(unsigned long data)
|
||||
{
|
||||
struct tegra_kbc *kbc = (struct tegra_kbc *)data;
|
||||
|
@ -455,10 +468,18 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
|
|||
row_cfg &= ~r_mask;
|
||||
col_cfg &= ~c_mask;
|
||||
|
||||
if (pdata->pin_cfg[i].is_row)
|
||||
switch (pdata->pin_cfg[i].type) {
|
||||
case PIN_CFG_ROW:
|
||||
row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
|
||||
else
|
||||
break;
|
||||
|
||||
case PIN_CFG_COL:
|
||||
col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
|
||||
break;
|
||||
|
||||
case PIN_CFG_IGNORE:
|
||||
break;
|
||||
}
|
||||
|
||||
writel(row_cfg, kbc->mmio + r_offs);
|
||||
writel(col_cfg, kbc->mmio + c_offs);
|
||||
|
@ -563,7 +584,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
|
|||
for (i = 0; i < KBC_MAX_GPIO; i++) {
|
||||
const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
|
||||
|
||||
if (pin_cfg->is_row) {
|
||||
switch (pin_cfg->type) {
|
||||
case PIN_CFG_ROW:
|
||||
if (pin_cfg->num >= KBC_MAX_ROW) {
|
||||
dev_err(dev,
|
||||
"pin_cfg[%d]: invalid row number %d\n",
|
||||
|
@ -571,13 +593,25 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
|
|||
return false;
|
||||
}
|
||||
(*num_rows)++;
|
||||
} else {
|
||||
break;
|
||||
|
||||
case PIN_CFG_COL:
|
||||
if (pin_cfg->num >= KBC_MAX_COL) {
|
||||
dev_err(dev,
|
||||
"pin_cfg[%d]: invalid column number %d\n",
|
||||
i, pin_cfg->num);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case PIN_CFG_IGNORE:
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(dev,
|
||||
"pin_cfg[%d]: invalid entry type %d\n",
|
||||
pin_cfg->type, pin_cfg->num);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -590,24 +624,25 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
|
|||
{
|
||||
struct tegra_kbc_platform_data *pdata;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 prop;
|
||||
int i;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
if (!of_property_read_u32(np, "debounce-delay", &prop))
|
||||
if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
|
||||
pdata->debounce_cnt = prop;
|
||||
|
||||
if (!of_property_read_u32(np, "repeat-delay", &prop))
|
||||
if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop))
|
||||
pdata->repeat_cnt = prop;
|
||||
|
||||
if (of_find_property(np, "needs-ghost-filter", NULL))
|
||||
if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
|
||||
pdata->use_ghost_filter = true;
|
||||
|
||||
if (of_find_property(np, "wakeup-source", NULL))
|
||||
if (of_find_property(np, "nvidia,wakeup-source", NULL))
|
||||
pdata->wakeup = true;
|
||||
|
||||
/*
|
||||
|
@ -616,14 +651,18 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
|
|||
*/
|
||||
for (i = 0; i < KBC_MAX_ROW; i++) {
|
||||
pdata->pin_cfg[i].num = i;
|
||||
pdata->pin_cfg[i].is_row = true;
|
||||
pdata->pin_cfg[i].type = PIN_CFG_ROW;
|
||||
}
|
||||
|
||||
for (i = 0; i < KBC_MAX_COL; i++) {
|
||||
pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
|
||||
pdata->pin_cfg[KBC_MAX_ROW + i].is_row = false;
|
||||
pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
|
||||
}
|
||||
|
||||
pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
|
||||
|
||||
/* FIXME: Add handling of linux,fn-keymap here */
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
|
@ -759,6 +798,9 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, kbc);
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
if (!pdev->dev.platform_data)
|
||||
matrix_keyboard_of_free_keymap(pdata->keymap_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
|
@ -773,8 +815,10 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
|
|||
input_free_device(input_dev);
|
||||
kfree(kbc);
|
||||
err_free_pdata:
|
||||
if (!pdev->dev.platform_data)
|
||||
if (!pdev->dev.platform_data) {
|
||||
matrix_keyboard_of_free_keymap(pdata->keymap_data);
|
||||
kfree(pdata);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -831,6 +875,8 @@ static int tegra_kbc_suspend(struct device *dev)
|
|||
msleep(30);
|
||||
|
||||
kbc->keypress_caused_wake = false;
|
||||
/* Enable keypress interrupt before going into suspend. */
|
||||
tegra_kbc_set_keypress_interrupt(kbc, true);
|
||||
enable_irq(kbc->irq);
|
||||
enable_irq_wake(kbc->irq);
|
||||
} else {
|
||||
|
@ -852,6 +898,8 @@ static int tegra_kbc_resume(struct device *dev)
|
|||
if (device_may_wakeup(&pdev->dev)) {
|
||||
disable_irq_wake(kbc->irq);
|
||||
tegra_kbc_setup_wakekeys(kbc, false);
|
||||
/* We will use fifo interrupts for key detection. */
|
||||
tegra_kbc_set_keypress_interrupt(kbc, false);
|
||||
|
||||
/* Restore the resident time of continuous polling mode. */
|
||||
writel(kbc->cp_to_wkup_dly, kbc->mmio + KBC_TO_CNT_0);
|
||||
|
|
|
@ -134,6 +134,18 @@ config INPUT_MAX8925_ONKEY
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called max8925_onkey.
|
||||
|
||||
config INPUT_MAX8997_HAPTIC
|
||||
tristate "MAXIM MAX8997 haptic controller support"
|
||||
depends on HAVE_PWM && MFD_MAX8997
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
This option enables device driver support for the haptic controller
|
||||
on MAXIM MAX8997 chip. This driver supports ff-memless interface
|
||||
from input framework.
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called max8997-haptic.
|
||||
|
||||
config INPUT_MC13783_PWRBUTTON
|
||||
tristate "MC13783 ON buttons"
|
||||
depends on MFD_MC13783
|
||||
|
@ -415,7 +427,7 @@ config INPUT_PCF8574
|
|||
tristate "PCF8574 Keypad input device"
|
||||
depends on I2C && EXPERIMENTAL
|
||||
help
|
||||
Say Y here if you want to support a keypad connetced via I2C
|
||||
Say Y here if you want to support a keypad connected via I2C
|
||||
with a PCF8574.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
@ -455,6 +467,16 @@ config INPUT_RB532_BUTTON
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called rb532_button.
|
||||
|
||||
config INPUT_DA9052_ONKEY
|
||||
tristate "Dialog DA9052/DA9053 Onkey"
|
||||
depends on PMIC_DA9052
|
||||
help
|
||||
Support the ONKEY of Dialog DA9052 PMICs as an input device
|
||||
reporting power button status.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called da9052_onkey.
|
||||
|
||||
config INPUT_DM355EVM
|
||||
tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
|
||||
depends on MFD_DM355EVM_MSP
|
||||
|
|
|
@ -21,6 +21,7 @@ obj-$(CONFIG_INPUT_CM109) += cm109.o
|
|||
obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
|
||||
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
|
||||
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
|
||||
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
|
||||
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
|
||||
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
|
||||
obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o
|
||||
|
@ -30,6 +31,7 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
|||
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
||||
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
||||
obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o
|
||||
|
|
|
@ -116,17 +116,7 @@ static struct i2c_driver ad714x_i2c_driver = {
|
|||
.id_table = ad714x_id,
|
||||
};
|
||||
|
||||
static int __init ad714x_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ad714x_i2c_driver);
|
||||
}
|
||||
module_init(ad714x_i2c_init);
|
||||
|
||||
static void __exit ad714x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ad714x_i2c_driver);
|
||||
}
|
||||
module_exit(ad714x_i2c_exit);
|
||||
module_i2c_driver(ad714x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor I2C Bus Driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
|
|
|
@ -123,17 +123,7 @@ static struct spi_driver ad714x_spi_driver = {
|
|||
.remove = __devexit_p(ad714x_spi_remove),
|
||||
};
|
||||
|
||||
static __init int ad714x_spi_init(void)
|
||||
{
|
||||
return spi_register_driver(&ad714x_spi_driver);
|
||||
}
|
||||
module_init(ad714x_spi_init);
|
||||
|
||||
static __exit void ad714x_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ad714x_spi_driver);
|
||||
}
|
||||
module_exit(ad714x_spi_exit);
|
||||
module_spi_driver(ad714x_spi_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor SPI Bus Driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
|
|
|
@ -148,17 +148,7 @@ static struct i2c_driver adxl34x_driver = {
|
|||
.id_table = adxl34x_id,
|
||||
};
|
||||
|
||||
static int __init adxl34x_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&adxl34x_driver);
|
||||
}
|
||||
module_init(adxl34x_i2c_init);
|
||||
|
||||
static void __exit adxl34x_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&adxl34x_driver);
|
||||
}
|
||||
module_exit(adxl34x_i2c_exit);
|
||||
module_i2c_driver(adxl34x_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer I2C Bus Driver");
|
||||
|
|
|
@ -129,17 +129,7 @@ static struct spi_driver adxl34x_driver = {
|
|||
.remove = __devexit_p(adxl34x_spi_remove),
|
||||
};
|
||||
|
||||
static int __init adxl34x_spi_init(void)
|
||||
{
|
||||
return spi_register_driver(&adxl34x_driver);
|
||||
}
|
||||
module_init(adxl34x_spi_init);
|
||||
|
||||
static void __exit adxl34x_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&adxl34x_driver);
|
||||
}
|
||||
module_exit(adxl34x_spi_exit);
|
||||
module_spi_driver(adxl34x_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer SPI Bus Driver");
|
||||
|
|
|
@ -673,19 +673,8 @@ static struct i2c_driver bma150_driver = {
|
|||
.remove = __devexit_p(bma150_remove),
|
||||
};
|
||||
|
||||
static int __init BMA150_init(void)
|
||||
{
|
||||
return i2c_add_driver(&bma150_driver);
|
||||
}
|
||||
|
||||
static void __exit BMA150_exit(void)
|
||||
{
|
||||
i2c_del_driver(&bma150_driver);
|
||||
}
|
||||
module_i2c_driver(bma150_driver);
|
||||
|
||||
MODULE_AUTHOR("Albert Zhang <xu.zhang@bosch-sensortec.com>");
|
||||
MODULE_DESCRIPTION("BMA150 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(BMA150_init);
|
||||
module_exit(BMA150_exit);
|
||||
|
|
|
@ -125,18 +125,7 @@ static struct i2c_driver cma3000_i2c_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init cma3000_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&cma3000_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit cma3000_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&cma3000_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(cma3000_i2c_init);
|
||||
module_exit(cma3000_i2c_exit);
|
||||
module_i2c_driver(cma3000_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CMA3000-D0x Accelerometer I2C Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
169
drivers/input/misc/da9052_onkey.c
Normal file
169
drivers/input/misc/da9052_onkey.c
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* ON pin driver for Dialog DA9052 PMICs
|
||||
*
|
||||
* Copyright(c) 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: David Dajun Chen <dchen@diasemi.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.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <linux/mfd/da9052/da9052.h>
|
||||
#include <linux/mfd/da9052/reg.h>
|
||||
|
||||
struct da9052_onkey {
|
||||
struct da9052 *da9052;
|
||||
struct input_dev *input;
|
||||
struct delayed_work work;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
static void da9052_onkey_query(struct da9052_onkey *onkey)
|
||||
{
|
||||
int key_stat;
|
||||
|
||||
key_stat = da9052_reg_read(onkey->da9052, DA9052_EVENT_B_REG);
|
||||
if (key_stat < 0) {
|
||||
dev_err(onkey->da9052->dev,
|
||||
"Failed to read onkey event %d\n", key_stat);
|
||||
} else {
|
||||
/*
|
||||
* Since interrupt for deassertion of ONKEY pin is not
|
||||
* generated, onkey event state determines the onkey
|
||||
* button state.
|
||||
*/
|
||||
key_stat &= DA9052_EVENTB_ENONKEY;
|
||||
input_report_key(onkey->input, KEY_POWER, key_stat);
|
||||
input_sync(onkey->input);
|
||||
}
|
||||
|
||||
/*
|
||||
* Interrupt is generated only when the ONKEY pin is asserted.
|
||||
* Hence the deassertion of the pin is simulated through work queue.
|
||||
*/
|
||||
if (key_stat)
|
||||
schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
|
||||
}
|
||||
|
||||
static void da9052_onkey_work(struct work_struct *work)
|
||||
{
|
||||
struct da9052_onkey *onkey = container_of(work, struct da9052_onkey,
|
||||
work.work);
|
||||
|
||||
da9052_onkey_query(onkey);
|
||||
}
|
||||
|
||||
static irqreturn_t da9052_onkey_irq(int irq, void *data)
|
||||
{
|
||||
struct da9052_onkey *onkey = data;
|
||||
|
||||
da9052_onkey_query(onkey);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit da9052_onkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct da9052_onkey *onkey;
|
||||
struct input_dev *input_dev;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
if (!da9052) {
|
||||
dev_err(&pdev->dev, "Failed to get the driver's data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "ONKEY");
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get an IRQ for input device, %d\n", irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
onkey = kzalloc(sizeof(*onkey), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!onkey || !input_dev) {
|
||||
dev_err(&pdev->dev, "Failed to allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
onkey->input = input_dev;
|
||||
onkey->da9052 = da9052;
|
||||
onkey->irq = irq;
|
||||
INIT_DELAYED_WORK(&onkey->work, da9052_onkey_work);
|
||||
|
||||
input_dev->name = "da9052-onkey";
|
||||
input_dev->phys = "da9052-onkey/input0";
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
__set_bit(KEY_POWER, input_dev->keybit);
|
||||
|
||||
error = request_threaded_irq(onkey->irq, NULL, da9052_onkey_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"ONKEY", onkey);
|
||||
if (error < 0) {
|
||||
dev_err(onkey->da9052->dev,
|
||||
"Failed to register ONKEY IRQ %d, error = %d\n",
|
||||
onkey->irq, error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = input_register_device(onkey->input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Unable to register input device, %d\n",
|
||||
error);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, onkey);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(onkey->irq, onkey);
|
||||
cancel_delayed_work_sync(&onkey->work);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(onkey);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit da9052_onkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9052_onkey *onkey = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(onkey->irq, onkey);
|
||||
cancel_delayed_work_sync(&onkey->work);
|
||||
|
||||
input_unregister_device(onkey->input);
|
||||
kfree(onkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9052_onkey_driver = {
|
||||
.probe = da9052_onkey_probe,
|
||||
.remove = __devexit_p(da9052_onkey_remove),
|
||||
.driver = {
|
||||
.name = "da9052-onkey",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(da9052_onkey_driver);
|
||||
|
||||
MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
|
||||
MODULE_DESCRIPTION("Onkey driver for DA9052");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:da9052-onkey");
|
|
@ -281,18 +281,7 @@ static struct i2c_driver gp2a_i2c_driver = {
|
|||
.id_table = gp2a_i2c_id,
|
||||
};
|
||||
|
||||
static int __init gp2a_init(void)
|
||||
{
|
||||
return i2c_add_driver(&gp2a_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit gp2a_exit(void)
|
||||
{
|
||||
i2c_del_driver(&gp2a_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(gp2a_init);
|
||||
module_exit(gp2a_exit);
|
||||
module_i2c_driver(gp2a_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>");
|
||||
MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver");
|
||||
|
|
|
@ -41,6 +41,14 @@
|
|||
#define PC1_ON (1 << 7)
|
||||
/* Data ready funtion enable bit: set during probe if using irq mode */
|
||||
#define DRDYE (1 << 5)
|
||||
/* DATA CONTROL REGISTER BITS */
|
||||
#define ODR12_5F 0
|
||||
#define ODR25F 1
|
||||
#define ODR50F 2
|
||||
#define ODR100F 3
|
||||
#define ODR200F 4
|
||||
#define ODR400F 5
|
||||
#define ODR800F 6
|
||||
/* INTERRUPT CONTROL REGISTER 1 BITS */
|
||||
/* Set these during probe if using irq mode */
|
||||
#define KXTJ9_IEL (1 << 3)
|
||||
|
@ -116,9 +124,13 @@ static void kxtj9_report_acceleration_data(struct kxtj9_data *tj9)
|
|||
if (err < 0)
|
||||
dev_err(&tj9->client->dev, "accelerometer data read failed\n");
|
||||
|
||||
x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]) >> tj9->shift;
|
||||
y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]) >> tj9->shift;
|
||||
z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]) >> tj9->shift;
|
||||
x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]);
|
||||
y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]);
|
||||
z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]);
|
||||
|
||||
x >>= tj9->shift;
|
||||
y >>= tj9->shift;
|
||||
z >>= tj9->shift;
|
||||
|
||||
input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x);
|
||||
input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y);
|
||||
|
@ -487,7 +499,7 @@ static int __devinit kxtj9_verify(struct kxtj9_data *tj9)
|
|||
goto out;
|
||||
}
|
||||
|
||||
retval = retval != 0x06 ? -EIO : 0;
|
||||
retval = (retval != 0x07 && retval != 0x08) ? -EIO : 0;
|
||||
|
||||
out:
|
||||
kxtj9_device_power_off(tj9);
|
||||
|
@ -537,7 +549,7 @@ static int __devinit kxtj9_probe(struct i2c_client *client,
|
|||
i2c_set_clientdata(client, tj9);
|
||||
|
||||
tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range;
|
||||
tj9->data_ctrl = tj9->pdata.data_odr_init;
|
||||
tj9->last_poll_interval = tj9->pdata.init_interval;
|
||||
|
||||
if (client->irq) {
|
||||
/* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */
|
||||
|
@ -655,17 +667,7 @@ static struct i2c_driver kxtj9_driver = {
|
|||
.id_table = kxtj9_id,
|
||||
};
|
||||
|
||||
static int __init kxtj9_init(void)
|
||||
{
|
||||
return i2c_add_driver(&kxtj9_driver);
|
||||
}
|
||||
module_init(kxtj9_init);
|
||||
|
||||
static void __exit kxtj9_exit(void)
|
||||
{
|
||||
i2c_del_driver(&kxtj9_driver);
|
||||
}
|
||||
module_exit(kxtj9_exit);
|
||||
module_i2c_driver(kxtj9_driver);
|
||||
|
||||
MODULE_DESCRIPTION("KXTJ9 accelerometer driver");
|
||||
MODULE_AUTHOR("Chris Hudson <chudson@kionix.com>");
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* max8925_onkey.c - MAX8925 ONKEY driver
|
||||
* MAX8925 ONKEY driver
|
||||
*
|
||||
* Copyright (C) 2009 Marvell International Ltd.
|
||||
* Haojian Zhuang <haojian.zhuang@marvell.com>
|
||||
|
@ -35,7 +35,7 @@ struct max8925_onkey_info {
|
|||
struct input_dev *idev;
|
||||
struct i2c_client *i2c;
|
||||
struct device *dev;
|
||||
int irq[2];
|
||||
unsigned int irq[2];
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -46,17 +46,14 @@ struct max8925_onkey_info {
|
|||
static irqreturn_t max8925_onkey_handler(int irq, void *data)
|
||||
{
|
||||
struct max8925_onkey_info *info = data;
|
||||
int ret, event;
|
||||
int state;
|
||||
|
||||
ret = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
|
||||
if (ret & SW_INPUT)
|
||||
event = 1;
|
||||
else
|
||||
event = 0;
|
||||
input_report_key(info->idev, KEY_POWER, event);
|
||||
state = max8925_reg_read(info->i2c, MAX8925_ON_OFF_STATUS);
|
||||
|
||||
input_report_key(info->idev, KEY_POWER, state & SW_INPUT);
|
||||
input_sync(info->idev);
|
||||
|
||||
dev_dbg(info->dev, "onkey event:%d\n", event);
|
||||
dev_dbg(info->dev, "onkey state:%d\n", state);
|
||||
|
||||
/* Enable hardreset to halt if system isn't shutdown on time */
|
||||
max8925_set_bits(info->i2c, MAX8925_SYSENSEL,
|
||||
|
@ -69,6 +66,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8925_onkey_info *info;
|
||||
struct input_dev *input;
|
||||
int irq[2], error;
|
||||
|
||||
irq[0] = platform_get_irq(pdev, 0);
|
||||
|
@ -76,6 +74,7 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
|
|||
dev_err(&pdev->dev, "No IRQ resource!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq[1] = platform_get_irq(pdev, 1);
|
||||
if (irq[1] < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource!\n");
|
||||
|
@ -83,11 +82,24 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
info = kzalloc(sizeof(struct max8925_onkey_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
input = input_allocate_device();
|
||||
if (!info || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
info->idev = input;
|
||||
info->i2c = chip->i2c;
|
||||
info->dev = &pdev->dev;
|
||||
info->irq[0] = irq[0];
|
||||
info->irq[1] = irq[1];
|
||||
|
||||
input->name = "max8925_on";
|
||||
input->phys = "max8925_on/input0";
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->dev.parent = &pdev->dev;
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
|
||||
irq[0] += chip->irq_base;
|
||||
irq[1] += chip->irq_base;
|
||||
|
||||
|
@ -96,60 +108,46 @@ static int __devinit max8925_onkey_probe(struct platform_device *pdev)
|
|||
if (error < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
irq[0], error);
|
||||
goto out;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = request_threaded_irq(irq[1], NULL, max8925_onkey_handler,
|
||||
IRQF_ONESHOT, "onkey-up", info);
|
||||
if (error < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
irq[1], error);
|
||||
goto out_irq;
|
||||
goto err_free_irq0;
|
||||
}
|
||||
|
||||
info->idev = input_allocate_device();
|
||||
if (!info->idev) {
|
||||
dev_err(chip->dev, "Failed to allocate input dev\n");
|
||||
error = -ENOMEM;
|
||||
goto out_input;
|
||||
}
|
||||
|
||||
info->idev->name = "max8925_on";
|
||||
info->idev->phys = "max8925_on/input0";
|
||||
info->idev->id.bustype = BUS_I2C;
|
||||
info->idev->dev.parent = &pdev->dev;
|
||||
info->irq[0] = irq[0];
|
||||
info->irq[1] = irq[1];
|
||||
info->idev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
info->idev->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER);
|
||||
|
||||
|
||||
error = input_register_device(info->idev);
|
||||
if (error) {
|
||||
dev_err(chip->dev, "Can't register input device: %d\n", error);
|
||||
goto out_reg;
|
||||
goto err_free_irq1;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
return 0;
|
||||
|
||||
out_reg:
|
||||
input_free_device(info->idev);
|
||||
out_input:
|
||||
free_irq(info->irq[1], info);
|
||||
out_irq:
|
||||
free_irq(info->irq[0], info);
|
||||
out:
|
||||
err_free_irq1:
|
||||
free_irq(irq[1], info);
|
||||
err_free_irq0:
|
||||
free_irq(irq[0], info);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(info);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit max8925_onkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
free_irq(info->irq[0], info);
|
||||
free_irq(info->irq[1], info);
|
||||
free_irq(info->irq[0] + chip->irq_base, info);
|
||||
free_irq(info->irq[1] + chip->irq_base, info);
|
||||
input_unregister_device(info->idev);
|
||||
kfree(info);
|
||||
|
||||
|
@ -158,10 +156,43 @@ static int __devexit max8925_onkey_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int max8925_onkey_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
chip->wakeup_flag |= 1 << info->irq[0];
|
||||
chip->wakeup_flag |= 1 << info->irq[1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max8925_onkey_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
chip->wakeup_flag &= ~(1 << info->irq[0]);
|
||||
chip->wakeup_flag &= ~(1 << info->irq[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
|
||||
|
||||
static struct platform_driver max8925_onkey_driver = {
|
||||
.driver = {
|
||||
.name = "max8925-onkey",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max8925_onkey_pm_ops,
|
||||
},
|
||||
.probe = max8925_onkey_probe,
|
||||
.remove = __devexit_p(max8925_onkey_remove),
|
||||
|
|
407
drivers/input/misc/max8997_haptic.c
Normal file
407
drivers/input/misc/max8997_haptic.c
Normal file
|
@ -0,0 +1,407 @@
|
|||
/*
|
||||
* MAX8997-haptic controller driver
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* Donggeun Kim <dg77.kim@samsung.com>
|
||||
*
|
||||
* This program is not provided / owned by Maxim Integrated Products.
|
||||
*
|
||||
* 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/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/max8997-private.h>
|
||||
#include <linux/mfd/max8997.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/* Haptic configuration 2 register */
|
||||
#define MAX8997_MOTOR_TYPE_SHIFT 7
|
||||
#define MAX8997_ENABLE_SHIFT 6
|
||||
#define MAX8997_MODE_SHIFT 5
|
||||
|
||||
/* Haptic driver configuration register */
|
||||
#define MAX8997_CYCLE_SHIFT 6
|
||||
#define MAX8997_SIG_PERIOD_SHIFT 4
|
||||
#define MAX8997_SIG_DUTY_SHIFT 2
|
||||
#define MAX8997_PWM_DUTY_SHIFT 0
|
||||
|
||||
struct max8997_haptic {
|
||||
struct device *dev;
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
struct regulator *regulator;
|
||||
|
||||
struct work_struct work;
|
||||
struct mutex mutex;
|
||||
|
||||
bool enabled;
|
||||
unsigned int level;
|
||||
|
||||
struct pwm_device *pwm;
|
||||
unsigned int pwm_period;
|
||||
enum max8997_haptic_pwm_divisor pwm_divisor;
|
||||
|
||||
enum max8997_haptic_motor_type type;
|
||||
enum max8997_haptic_pulse_mode mode;
|
||||
|
||||
unsigned int internal_mode_pattern;
|
||||
unsigned int pattern_cycle;
|
||||
unsigned int pattern_signal_period;
|
||||
};
|
||||
|
||||
static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE) {
|
||||
unsigned int duty = chip->pwm_period * chip->level / 100;
|
||||
ret = pwm_config(chip->pwm, duty, chip->pwm_period);
|
||||
} else {
|
||||
int i;
|
||||
u8 duty_index = 0;
|
||||
|
||||
for (i = 0; i <= 64; i++) {
|
||||
if (chip->level <= i * 100 / 64) {
|
||||
duty_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (chip->internal_mode_pattern) {
|
||||
case 0:
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
|
||||
break;
|
||||
case 1:
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
|
||||
break;
|
||||
case 2:
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
|
||||
break;
|
||||
case 3:
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max8997_haptic_configure(struct max8997_haptic *chip)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
|
||||
chip->enabled << MAX8997_ENABLE_SHIFT |
|
||||
chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
|
||||
max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);
|
||||
|
||||
if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
|
||||
value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
|
||||
chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
|
||||
chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
|
||||
chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_DRVCONF, value);
|
||||
|
||||
switch (chip->internal_mode_pattern) {
|
||||
case 0:
|
||||
value = chip->pattern_cycle << 4;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF1, value);
|
||||
value = chip->pattern_signal_period;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGCONF1, value);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
value = chip->pattern_cycle;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF1, value);
|
||||
value = chip->pattern_signal_period;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGCONF2, value);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
value = chip->pattern_cycle << 4;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF2, value);
|
||||
value = chip->pattern_signal_period;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGCONF3, value);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
value = chip->pattern_cycle;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_CYCLECONF2, value);
|
||||
value = chip->pattern_signal_period;
|
||||
max8997_write_reg(chip->client,
|
||||
MAX8997_HAPTIC_REG_SIGCONF4, value);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void max8997_haptic_enable(struct max8997_haptic *chip)
|
||||
{
|
||||
int error;
|
||||
|
||||
mutex_lock(&chip->mutex);
|
||||
|
||||
error = max8997_haptic_set_duty_cycle(chip);
|
||||
if (error) {
|
||||
dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!chip->enabled) {
|
||||
chip->enabled = true;
|
||||
regulator_enable(chip->regulator);
|
||||
max8997_haptic_configure(chip);
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
||||
pwm_enable(chip->pwm);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->mutex);
|
||||
}
|
||||
|
||||
static void max8997_haptic_disable(struct max8997_haptic *chip)
|
||||
{
|
||||
mutex_lock(&chip->mutex);
|
||||
|
||||
if (chip->enabled) {
|
||||
chip->enabled = false;
|
||||
max8997_haptic_configure(chip);
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
||||
pwm_disable(chip->pwm);
|
||||
regulator_disable(chip->regulator);
|
||||
}
|
||||
|
||||
mutex_unlock(&chip->mutex);
|
||||
}
|
||||
|
||||
static void max8997_haptic_play_effect_work(struct work_struct *work)
|
||||
{
|
||||
struct max8997_haptic *chip =
|
||||
container_of(work, struct max8997_haptic, work);
|
||||
|
||||
if (chip->level)
|
||||
max8997_haptic_enable(chip);
|
||||
else
|
||||
max8997_haptic_disable(chip);
|
||||
}
|
||||
|
||||
static int max8997_haptic_play_effect(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct max8997_haptic *chip = input_get_drvdata(dev);
|
||||
|
||||
chip->level = effect->u.rumble.strong_magnitude;
|
||||
if (!chip->level)
|
||||
chip->level = effect->u.rumble.weak_magnitude;
|
||||
|
||||
schedule_work(&chip->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max8997_haptic_close(struct input_dev *dev)
|
||||
{
|
||||
struct max8997_haptic *chip = input_get_drvdata(dev);
|
||||
|
||||
cancel_work_sync(&chip->work);
|
||||
max8997_haptic_disable(chip);
|
||||
}
|
||||
|
||||
static int __devinit max8997_haptic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
|
||||
const struct max8997_platform_data *pdata =
|
||||
dev_get_platdata(iodev->dev);
|
||||
const struct max8997_haptic_platform_data *haptic_pdata =
|
||||
pdata->haptic_pdata;
|
||||
struct max8997_haptic *chip;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
if (!haptic_pdata) {
|
||||
dev_err(&pdev->dev, "no haptic platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!chip || !input_dev) {
|
||||
dev_err(&pdev->dev, "unable to allocate memory\n");
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
INIT_WORK(&chip->work, max8997_haptic_play_effect_work);
|
||||
mutex_init(&chip->mutex);
|
||||
|
||||
chip->client = iodev->haptic;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->input_dev = input_dev;
|
||||
chip->pwm_period = haptic_pdata->pwm_period;
|
||||
chip->type = haptic_pdata->type;
|
||||
chip->mode = haptic_pdata->mode;
|
||||
chip->pwm_divisor = haptic_pdata->pwm_divisor;
|
||||
|
||||
switch (chip->mode) {
|
||||
case MAX8997_INTERNAL_MODE:
|
||||
chip->internal_mode_pattern =
|
||||
haptic_pdata->internal_mode_pattern;
|
||||
chip->pattern_cycle = haptic_pdata->pattern_cycle;
|
||||
chip->pattern_signal_period =
|
||||
haptic_pdata->pattern_signal_period;
|
||||
break;
|
||||
|
||||
case MAX8997_EXTERNAL_MODE:
|
||||
chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
|
||||
"max8997-haptic");
|
||||
if (IS_ERR(chip->pwm)) {
|
||||
error = PTR_ERR(chip->pwm);
|
||||
dev_err(&pdev->dev,
|
||||
"unable to request PWM for haptic, error: %d\n",
|
||||
error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev,
|
||||
"Invalid chip mode specified (%d)\n", chip->mode);
|
||||
error = -EINVAL;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
chip->regulator = regulator_get(&pdev->dev, "inmotor");
|
||||
if (IS_ERR(chip->regulator)) {
|
||||
error = PTR_ERR(chip->regulator);
|
||||
dev_err(&pdev->dev,
|
||||
"unable to get regulator, error: %d\n",
|
||||
error);
|
||||
goto err_free_pwm;
|
||||
}
|
||||
|
||||
input_dev->name = "max8997-haptic";
|
||||
input_dev->id.version = 1;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_dev->close = max8997_haptic_close;
|
||||
input_set_drvdata(input_dev, chip);
|
||||
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
|
||||
|
||||
error = input_ff_create_memless(input_dev, NULL,
|
||||
max8997_haptic_play_effect);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to create FF device, error: %d\n",
|
||||
error);
|
||||
goto err_put_regulator;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to register input device, error: %d\n",
|
||||
error);
|
||||
goto err_destroy_ff;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
return 0;
|
||||
|
||||
err_destroy_ff:
|
||||
input_ff_destroy(input_dev);
|
||||
err_put_regulator:
|
||||
regulator_put(chip->regulator);
|
||||
err_free_pwm:
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
||||
pwm_free(chip->pwm);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(chip);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit max8997_haptic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max8997_haptic *chip = platform_get_drvdata(pdev);
|
||||
|
||||
input_unregister_device(chip->input_dev);
|
||||
regulator_put(chip->regulator);
|
||||
|
||||
if (chip->mode == MAX8997_EXTERNAL_MODE)
|
||||
pwm_free(chip->pwm);
|
||||
|
||||
kfree(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int max8997_haptic_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct max8997_haptic *chip = platform_get_drvdata(pdev);
|
||||
|
||||
max8997_haptic_disable(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
|
||||
|
||||
static const struct platform_device_id max8997_haptic_id[] = {
|
||||
{ "max8997-haptic", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max8997_haptic_id);
|
||||
|
||||
static struct platform_driver max8997_haptic_driver = {
|
||||
.driver = {
|
||||
.name = "max8997-haptic",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &max8997_haptic_pm_ops,
|
||||
},
|
||||
.probe = max8997_haptic_probe,
|
||||
.remove = __devexit_p(max8997_haptic_remove),
|
||||
.id_table = max8997_haptic_id,
|
||||
};
|
||||
module_platform_driver(max8997_haptic_driver);
|
||||
|
||||
MODULE_ALIAS("platform:max8997-haptic");
|
||||
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("max8997_haptic driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -247,17 +247,7 @@ static struct i2c_driver mma8450_driver = {
|
|||
.id_table = mma8450_id,
|
||||
};
|
||||
|
||||
static int __init mma8450_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mma8450_driver);
|
||||
}
|
||||
module_init(mma8450_init);
|
||||
|
||||
static void __exit mma8450_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mma8450_driver);
|
||||
}
|
||||
module_exit(mma8450_exit);
|
||||
module_i2c_driver(mma8450_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver");
|
||||
|
|
|
@ -475,17 +475,7 @@ static struct i2c_driver mpu3050_i2c_driver = {
|
|||
.id_table = mpu3050_ids,
|
||||
};
|
||||
|
||||
static int __init mpu3050_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mpu3050_i2c_driver);
|
||||
}
|
||||
module_init(mpu3050_init);
|
||||
|
||||
static void __exit mpu3050_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mpu3050_i2c_driver);
|
||||
}
|
||||
module_exit(mpu3050_exit);
|
||||
module_i2c_driver(mpu3050_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Wistron Corp.");
|
||||
MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver");
|
||||
|
|
|
@ -216,17 +216,7 @@ static struct i2c_driver pcf8574_kp_driver = {
|
|||
.id_table = pcf8574_kp_id,
|
||||
};
|
||||
|
||||
static int __init pcf8574_kp_init(void)
|
||||
{
|
||||
return i2c_add_driver(&pcf8574_kp_driver);
|
||||
}
|
||||
module_init(pcf8574_kp_init);
|
||||
|
||||
static void __exit pcf8574_kp_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pcf8574_kp_driver);
|
||||
}
|
||||
module_exit(pcf8574_kp_exit);
|
||||
module_i2c_driver(pcf8574_kp_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich");
|
||||
MODULE_DESCRIPTION("Keypad input driver for 16 keys connected to PCF8574");
|
||||
|
|
|
@ -172,7 +172,7 @@ static void twl4030_vibra_close(struct input_dev *input)
|
|||
}
|
||||
|
||||
/*** Module ***/
|
||||
#if CONFIG_PM_SLEEP
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int twl4030_vibra_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
|
|
@ -322,4 +322,21 @@ config MOUSE_SYNAPTICS_I2C
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_i2c.
|
||||
|
||||
config MOUSE_SYNAPTICS_USB
|
||||
tristate "Synaptics USB device support"
|
||||
depends on USB_ARCH_HAS_HCD
|
||||
select USB
|
||||
help
|
||||
Say Y here if you want to use a Synaptics USB touchpad or pointing
|
||||
stick.
|
||||
|
||||
While these devices emulate an USB mouse by default and can be used
|
||||
with standard usbhid driver, this driver, together with its X.Org
|
||||
counterpart, allows you to fully utilize capabilities of the device.
|
||||
More information can be found at:
|
||||
<http://jan-steinhoff.de/linux/synaptics-usb.html>
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_usb.
|
||||
|
||||
endif
|
||||
|
|
|
@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
|
|||
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
|
||||
obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
|
||||
obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
|
||||
obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
|
||||
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
|
||||
|
||||
psmouse-objs := psmouse-base.o synaptics.o
|
||||
|
|
|
@ -433,6 +433,7 @@ static void setup_events_to_report(struct input_dev *input_dev,
|
|||
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
if (cfg->caps & HAS_INTEGRATED_BUTTON)
|
||||
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
|
||||
|
||||
|
|
|
@ -640,7 +640,6 @@ static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate)
|
|||
|
||||
static int hgpk_force_recalibrate(struct psmouse *psmouse)
|
||||
{
|
||||
struct ps2dev *ps2dev = &psmouse->ps2dev;
|
||||
struct hgpk_data *priv = psmouse->private;
|
||||
int err;
|
||||
|
||||
|
@ -669,12 +668,9 @@ static int hgpk_force_recalibrate(struct psmouse *psmouse)
|
|||
* we don't have a good way to deal with it. The 2s window stuff
|
||||
* (below) is our best option for now.
|
||||
*/
|
||||
|
||||
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
|
||||
if (psmouse_activate(psmouse))
|
||||
return -1;
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
|
||||
if (tpdebug)
|
||||
psmouse_dbg(psmouse, "touchpad reactivated\n");
|
||||
|
||||
|
@ -733,8 +729,7 @@ static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable)
|
|||
}
|
||||
|
||||
/* should be all set, enable the touchpad */
|
||||
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
psmouse_activate(psmouse);
|
||||
psmouse_dbg(psmouse, "Touchpad powered up.\n");
|
||||
} else {
|
||||
psmouse_dbg(psmouse, "Powering off touchpad.\n");
|
||||
|
|
|
@ -1092,28 +1092,33 @@ static void psmouse_initialize(struct psmouse *psmouse)
|
|||
* psmouse_activate() enables the mouse so that we get motion reports from it.
|
||||
*/
|
||||
|
||||
static void psmouse_activate(struct psmouse *psmouse)
|
||||
int psmouse_activate(struct psmouse *psmouse)
|
||||
{
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
|
||||
psmouse_warn(psmouse, "Failed to enable mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* psmouse_deactivate() puts the mouse into poll mode so that we don't get motion
|
||||
* reports from it unless we explicitly request it.
|
||||
*/
|
||||
|
||||
static void psmouse_deactivate(struct psmouse *psmouse)
|
||||
int psmouse_deactivate(struct psmouse *psmouse)
|
||||
{
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
|
||||
if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) {
|
||||
psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n",
|
||||
psmouse->ps2dev.serio->phys);
|
||||
return -1;
|
||||
}
|
||||
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -105,6 +105,8 @@ int psmouse_reset(struct psmouse *psmouse);
|
|||
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
|
||||
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
|
||||
psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse);
|
||||
int psmouse_activate(struct psmouse *psmouse);
|
||||
int psmouse_deactivate(struct psmouse *psmouse);
|
||||
|
||||
struct psmouse_attribute {
|
||||
struct device_attribute dattr;
|
||||
|
|
|
@ -90,8 +90,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
|
|||
* to do that for writes because sysfs set helper does this for
|
||||
* us.
|
||||
*/
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
psmouse_deactivate(psmouse);
|
||||
|
||||
ps2_begin_command(ps2dev);
|
||||
|
||||
|
@ -128,8 +127,7 @@ static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val)
|
|||
|
||||
out:
|
||||
ps2_end_command(ps2dev);
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
psmouse_activate(psmouse);
|
||||
dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n",
|
||||
reg_addr, *reg_val, rc);
|
||||
return rc;
|
||||
|
@ -213,8 +211,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
|
|||
unsigned char param[3];
|
||||
int rc = -1;
|
||||
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
|
||||
psmouse_deactivate(psmouse);
|
||||
|
||||
ps2_begin_command(ps2dev);
|
||||
|
||||
|
@ -239,8 +236,7 @@ static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val)
|
|||
|
||||
out:
|
||||
ps2_end_command(ps2dev);
|
||||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
|
||||
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
|
||||
psmouse_activate(psmouse);
|
||||
dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n",
|
||||
*reg_val, rc);
|
||||
return rc;
|
||||
|
|
|
@ -672,18 +672,7 @@ static struct i2c_driver synaptics_i2c_driver = {
|
|||
.id_table = synaptics_i2c_id_table,
|
||||
};
|
||||
|
||||
static int __init synaptics_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&synaptics_i2c_driver);
|
||||
}
|
||||
|
||||
static void __exit synaptics_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&synaptics_i2c_driver);
|
||||
}
|
||||
|
||||
module_init(synaptics_i2c_init);
|
||||
module_exit(synaptics_i2c_exit);
|
||||
module_i2c_driver(synaptics_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Synaptics I2C touchpad driver");
|
||||
MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab");
|
||||
|
|
557
drivers/input/mouse/synaptics_usb.c
Normal file
557
drivers/input/mouse/synaptics_usb.c
Normal file
|
@ -0,0 +1,557 @@
|
|||
/*
|
||||
* USB Synaptics device driver
|
||||
*
|
||||
* Copyright (c) 2002 Rob Miller (rob@inpharmatica . co . uk)
|
||||
* Copyright (c) 2003 Ron Lee (ron@debian.org)
|
||||
* cPad driver for kernel 2.4
|
||||
*
|
||||
* Copyright (c) 2004 Jan Steinhoff (cpad@jan-steinhoff . de)
|
||||
* Copyright (c) 2004 Ron Lee (ron@debian.org)
|
||||
* rewritten for kernel 2.6
|
||||
*
|
||||
* cPad display character device part is not included. It can be found at
|
||||
* http://jan-steinhoff.de/linux/synaptics-usb.html
|
||||
*
|
||||
* Bases on: usb_skeleton.c v2.2 by Greg Kroah-Hartman
|
||||
* drivers/hid/usbhid/usbmouse.c by Vojtech Pavlik
|
||||
* drivers/input/mouse/synaptics.c by Peter Osterlund
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Trademarks are the property of their respective owners.
|
||||
*/
|
||||
|
||||
/*
|
||||
* There are three different types of Synaptics USB devices: Touchpads,
|
||||
* touchsticks (or trackpoints), and touchscreens. Touchpads are well supported
|
||||
* by this driver, touchstick support has not been tested much yet, and
|
||||
* touchscreens have not been tested at all.
|
||||
*
|
||||
* Up to three alternate settings are possible:
|
||||
* setting 0: one int endpoint for relative movement (used by usbhid.ko)
|
||||
* setting 1: one int endpoint for absolute finger position
|
||||
* setting 2 (cPad only): one int endpoint for absolute finger position and
|
||||
* two bulk endpoints for the display (in/out)
|
||||
* This driver uses setting 1.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/usb/input.h>
|
||||
|
||||
#define USB_VENDOR_ID_SYNAPTICS 0x06cb
|
||||
#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 /* Synaptics USB TouchPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 /* Integrated USB TouchPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 /* Synaptics cPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 /* Synaptics TouchScreen */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 /* Synaptics USB Styk */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 /* Synaptics USB WheelPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 /* Composite USB TouchPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 /* Wireless TouchPad */
|
||||
#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 /* DisplayPad */
|
||||
|
||||
#define SYNUSB_TOUCHPAD (1 << 0)
|
||||
#define SYNUSB_STICK (1 << 1)
|
||||
#define SYNUSB_TOUCHSCREEN (1 << 2)
|
||||
#define SYNUSB_AUXDISPLAY (1 << 3) /* For cPad */
|
||||
#define SYNUSB_COMBO (1 << 4) /* Composite device (TP + stick) */
|
||||
#define SYNUSB_IO_ALWAYS (1 << 5)
|
||||
|
||||
#define USB_DEVICE_SYNAPTICS(prod, kind) \
|
||||
USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, \
|
||||
USB_DEVICE_ID_SYNAPTICS_##prod), \
|
||||
.driver_info = (kind),
|
||||
|
||||
#define SYNUSB_RECV_SIZE 8
|
||||
|
||||
#define XMIN_NOMINAL 1472
|
||||
#define XMAX_NOMINAL 5472
|
||||
#define YMIN_NOMINAL 1408
|
||||
#define YMAX_NOMINAL 4448
|
||||
|
||||
struct synusb {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *intf;
|
||||
struct urb *urb;
|
||||
unsigned char *data;
|
||||
|
||||
/* input device related data structures */
|
||||
struct input_dev *input;
|
||||
char name[128];
|
||||
char phys[64];
|
||||
|
||||
/* characteristics of the device */
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
static void synusb_report_buttons(struct synusb *synusb)
|
||||
{
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
|
||||
input_report_key(input_dev, BTN_LEFT, synusb->data[1] & 0x04);
|
||||
input_report_key(input_dev, BTN_RIGHT, synusb->data[1] & 0x01);
|
||||
input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x02);
|
||||
}
|
||||
|
||||
static void synusb_report_stick(struct synusb *synusb)
|
||||
{
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
int x, y;
|
||||
unsigned int pressure;
|
||||
|
||||
pressure = synusb->data[6];
|
||||
x = (s16)(be16_to_cpup((__be16 *)&synusb->data[2]) << 3) >> 7;
|
||||
y = (s16)(be16_to_cpup((__be16 *)&synusb->data[4]) << 3) >> 7;
|
||||
|
||||
if (pressure > 0) {
|
||||
input_report_rel(input_dev, REL_X, x);
|
||||
input_report_rel(input_dev, REL_Y, -y);
|
||||
}
|
||||
|
||||
input_report_abs(input_dev, ABS_PRESSURE, pressure);
|
||||
|
||||
synusb_report_buttons(synusb);
|
||||
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static void synusb_report_touchpad(struct synusb *synusb)
|
||||
{
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
unsigned int num_fingers, tool_width;
|
||||
unsigned int x, y;
|
||||
unsigned int pressure, w;
|
||||
|
||||
pressure = synusb->data[6];
|
||||
x = be16_to_cpup((__be16 *)&synusb->data[2]);
|
||||
y = be16_to_cpup((__be16 *)&synusb->data[4]);
|
||||
w = synusb->data[0] & 0x0f;
|
||||
|
||||
if (pressure > 0) {
|
||||
num_fingers = 1;
|
||||
tool_width = 5;
|
||||
switch (w) {
|
||||
case 0 ... 1:
|
||||
num_fingers = 2 + w;
|
||||
break;
|
||||
|
||||
case 2: /* pen, pretend its a finger */
|
||||
break;
|
||||
|
||||
case 4 ... 15:
|
||||
tool_width = w;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
num_fingers = 0;
|
||||
tool_width = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Post events
|
||||
* BTN_TOUCH has to be first as mousedev relies on it when doing
|
||||
* absolute -> relative conversion
|
||||
*/
|
||||
|
||||
if (pressure > 30)
|
||||
input_report_key(input_dev, BTN_TOUCH, 1);
|
||||
if (pressure < 25)
|
||||
input_report_key(input_dev, BTN_TOUCH, 0);
|
||||
|
||||
if (num_fingers > 0) {
|
||||
input_report_abs(input_dev, ABS_X, x);
|
||||
input_report_abs(input_dev, ABS_Y,
|
||||
YMAX_NOMINAL + YMIN_NOMINAL - y);
|
||||
}
|
||||
|
||||
input_report_abs(input_dev, ABS_PRESSURE, pressure);
|
||||
input_report_abs(input_dev, ABS_TOOL_WIDTH, tool_width);
|
||||
|
||||
input_report_key(input_dev, BTN_TOOL_FINGER, num_fingers == 1);
|
||||
input_report_key(input_dev, BTN_TOOL_DOUBLETAP, num_fingers == 2);
|
||||
input_report_key(input_dev, BTN_TOOL_TRIPLETAP, num_fingers == 3);
|
||||
|
||||
synusb_report_buttons(synusb);
|
||||
if (synusb->flags & SYNUSB_AUXDISPLAY)
|
||||
input_report_key(input_dev, BTN_MIDDLE, synusb->data[1] & 0x08);
|
||||
|
||||
input_sync(input_dev);
|
||||
}
|
||||
|
||||
static void synusb_irq(struct urb *urb)
|
||||
{
|
||||
struct synusb *synusb = urb->context;
|
||||
int error;
|
||||
|
||||
/* Check our status in case we need to bail out early. */
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
usb_mark_last_busy(synusb->udev);
|
||||
break;
|
||||
|
||||
/* Device went away so don't keep trying to read from it. */
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
return;
|
||||
|
||||
default:
|
||||
goto resubmit;
|
||||
break;
|
||||
}
|
||||
|
||||
if (synusb->flags & SYNUSB_STICK)
|
||||
synusb_report_stick(synusb);
|
||||
else
|
||||
synusb_report_touchpad(synusb);
|
||||
|
||||
resubmit:
|
||||
error = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (error && error != -EPERM)
|
||||
dev_err(&synusb->intf->dev,
|
||||
"%s - usb_submit_urb failed with result: %d",
|
||||
__func__, error);
|
||||
}
|
||||
|
||||
static struct usb_endpoint_descriptor *
|
||||
synusb_get_in_endpoint(struct usb_host_interface *iface)
|
||||
{
|
||||
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_is_int_in(endpoint)) {
|
||||
/* we found our interrupt in endpoint */
|
||||
return endpoint;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int synusb_open(struct input_dev *dev)
|
||||
{
|
||||
struct synusb *synusb = input_get_drvdata(dev);
|
||||
int retval;
|
||||
|
||||
retval = usb_autopm_get_interface(synusb->intf);
|
||||
if (retval) {
|
||||
dev_err(&synusb->intf->dev,
|
||||
"%s - usb_autopm_get_interface failed, error: %d\n",
|
||||
__func__, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = usb_submit_urb(synusb->urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
dev_err(&synusb->intf->dev,
|
||||
"%s - usb_submit_urb failed, error: %d\n",
|
||||
__func__, retval);
|
||||
retval = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
synusb->intf->needs_remote_wakeup = 1;
|
||||
|
||||
out:
|
||||
usb_autopm_put_interface(synusb->intf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synusb_close(struct input_dev *dev)
|
||||
{
|
||||
struct synusb *synusb = input_get_drvdata(dev);
|
||||
int autopm_error;
|
||||
|
||||
autopm_error = usb_autopm_get_interface(synusb->intf);
|
||||
|
||||
usb_kill_urb(synusb->urb);
|
||||
synusb->intf->needs_remote_wakeup = 0;
|
||||
|
||||
if (!autopm_error)
|
||||
usb_autopm_put_interface(synusb->intf);
|
||||
}
|
||||
|
||||
static int synusb_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
struct synusb *synusb;
|
||||
struct input_dev *input_dev;
|
||||
unsigned int intf_num = intf->cur_altsetting->desc.bInterfaceNumber;
|
||||
unsigned int altsetting = min(intf->num_altsetting, 1U);
|
||||
int error;
|
||||
|
||||
error = usb_set_interface(udev, intf_num, altsetting);
|
||||
if (error) {
|
||||
dev_err(&udev->dev,
|
||||
"Can not set alternate setting to %i, error: %i",
|
||||
altsetting, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
ep = synusb_get_in_endpoint(intf->cur_altsetting);
|
||||
if (!ep)
|
||||
return -ENODEV;
|
||||
|
||||
synusb = kzalloc(sizeof(*synusb), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!synusb || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
synusb->udev = udev;
|
||||
synusb->intf = intf;
|
||||
synusb->input = input_dev;
|
||||
|
||||
synusb->flags = id->driver_info;
|
||||
if (synusb->flags & SYNUSB_COMBO) {
|
||||
/*
|
||||
* This is a combo device, we need to set proper
|
||||
* capability, depending on the interface.
|
||||
*/
|
||||
synusb->flags |= intf_num == 1 ?
|
||||
SYNUSB_STICK : SYNUSB_TOUCHPAD;
|
||||
}
|
||||
|
||||
synusb->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!synusb->urb) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
synusb->data = usb_alloc_coherent(udev, SYNUSB_RECV_SIZE, GFP_KERNEL,
|
||||
&synusb->urb->transfer_dma);
|
||||
if (!synusb->data) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_urb;
|
||||
}
|
||||
|
||||
usb_fill_int_urb(synusb->urb, udev,
|
||||
usb_rcvintpipe(udev, ep->bEndpointAddress),
|
||||
synusb->data, SYNUSB_RECV_SIZE,
|
||||
synusb_irq, synusb,
|
||||
ep->bInterval);
|
||||
synusb->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
if (udev->manufacturer)
|
||||
strlcpy(synusb->name, udev->manufacturer,
|
||||
sizeof(synusb->name));
|
||||
|
||||
if (udev->product) {
|
||||
if (udev->manufacturer)
|
||||
strlcat(synusb->name, " ", sizeof(synusb->name));
|
||||
strlcat(synusb->name, udev->product, sizeof(synusb->name));
|
||||
}
|
||||
|
||||
if (!strlen(synusb->name))
|
||||
snprintf(synusb->name, sizeof(synusb->name),
|
||||
"USB Synaptics Device %04x:%04x",
|
||||
le16_to_cpu(udev->descriptor.idVendor),
|
||||
le16_to_cpu(udev->descriptor.idProduct));
|
||||
|
||||
if (synusb->flags & SYNUSB_STICK)
|
||||
strlcat(synusb->name, " (Stick) ", sizeof(synusb->name));
|
||||
|
||||
usb_make_path(udev, synusb->phys, sizeof(synusb->phys));
|
||||
strlcat(synusb->phys, "/input0", sizeof(synusb->phys));
|
||||
|
||||
input_dev->name = synusb->name;
|
||||
input_dev->phys = synusb->phys;
|
||||
usb_to_input_id(udev, &input_dev->id);
|
||||
input_dev->dev.parent = &synusb->intf->dev;
|
||||
|
||||
if (!(synusb->flags & SYNUSB_IO_ALWAYS)) {
|
||||
input_dev->open = synusb_open;
|
||||
input_dev->close = synusb_close;
|
||||
}
|
||||
|
||||
input_set_drvdata(input_dev, synusb);
|
||||
|
||||
__set_bit(EV_ABS, input_dev->evbit);
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
|
||||
if (synusb->flags & SYNUSB_STICK) {
|
||||
__set_bit(EV_REL, input_dev->evbit);
|
||||
__set_bit(REL_X, input_dev->relbit);
|
||||
__set_bit(REL_Y, input_dev->relbit);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 127, 0, 0);
|
||||
} else {
|
||||
input_set_abs_params(input_dev, ABS_X,
|
||||
XMIN_NOMINAL, XMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y,
|
||||
YMIN_NOMINAL, YMAX_NOMINAL, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
|
||||
__set_bit(BTN_TOUCH, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
|
||||
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
|
||||
}
|
||||
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
__set_bit(BTN_RIGHT, input_dev->keybit);
|
||||
__set_bit(BTN_MIDDLE, input_dev->keybit);
|
||||
|
||||
usb_set_intfdata(intf, synusb);
|
||||
|
||||
if (synusb->flags & SYNUSB_IO_ALWAYS) {
|
||||
error = synusb_open(input_dev);
|
||||
if (error)
|
||||
goto err_free_dma;
|
||||
}
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(&udev->dev,
|
||||
"Failed to register input device, error %d\n",
|
||||
error);
|
||||
goto err_stop_io;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_io:
|
||||
if (synusb->flags & SYNUSB_IO_ALWAYS)
|
||||
synusb_close(synusb->input);
|
||||
err_free_dma:
|
||||
usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
|
||||
synusb->urb->transfer_dma);
|
||||
err_free_urb:
|
||||
usb_free_urb(synusb->urb);
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(synusb);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void synusb_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct synusb *synusb = usb_get_intfdata(intf);
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
if (synusb->flags & SYNUSB_IO_ALWAYS)
|
||||
synusb_close(synusb->input);
|
||||
|
||||
input_unregister_device(synusb->input);
|
||||
|
||||
usb_free_coherent(udev, SYNUSB_RECV_SIZE, synusb->data,
|
||||
synusb->urb->transfer_dma);
|
||||
usb_free_urb(synusb->urb);
|
||||
kfree(synusb);
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
}
|
||||
|
||||
static int synusb_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
{
|
||||
struct synusb *synusb = usb_get_intfdata(intf);
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
usb_kill_urb(synusb->urb);
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synusb_resume(struct usb_interface *intf)
|
||||
{
|
||||
struct synusb *synusb = usb_get_intfdata(intf);
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
|
||||
usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
|
||||
retval = -EIO;
|
||||
}
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synusb_pre_reset(struct usb_interface *intf)
|
||||
{
|
||||
struct synusb *synusb = usb_get_intfdata(intf);
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
|
||||
mutex_lock(&input_dev->mutex);
|
||||
usb_kill_urb(synusb->urb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synusb_post_reset(struct usb_interface *intf)
|
||||
{
|
||||
struct synusb *synusb = usb_get_intfdata(intf);
|
||||
struct input_dev *input_dev = synusb->input;
|
||||
int retval = 0;
|
||||
|
||||
if ((input_dev->users || (synusb->flags & SYNUSB_IO_ALWAYS)) &&
|
||||
usb_submit_urb(synusb->urb, GFP_NOIO) < 0) {
|
||||
retval = -EIO;
|
||||
}
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synusb_reset_resume(struct usb_interface *intf)
|
||||
{
|
||||
return synusb_resume(intf);
|
||||
}
|
||||
|
||||
static struct usb_device_id synusb_idtable[] = {
|
||||
{ USB_DEVICE_SYNAPTICS(TP, SYNUSB_TOUCHPAD) },
|
||||
{ USB_DEVICE_SYNAPTICS(INT_TP, SYNUSB_TOUCHPAD) },
|
||||
{ USB_DEVICE_SYNAPTICS(CPAD,
|
||||
SYNUSB_TOUCHPAD | SYNUSB_AUXDISPLAY | SYNUSB_IO_ALWAYS) },
|
||||
{ USB_DEVICE_SYNAPTICS(TS, SYNUSB_TOUCHSCREEN) },
|
||||
{ USB_DEVICE_SYNAPTICS(STICK, SYNUSB_STICK) },
|
||||
{ USB_DEVICE_SYNAPTICS(WP, SYNUSB_TOUCHPAD) },
|
||||
{ USB_DEVICE_SYNAPTICS(COMP_TP, SYNUSB_COMBO) },
|
||||
{ USB_DEVICE_SYNAPTICS(WTP, SYNUSB_TOUCHPAD) },
|
||||
{ USB_DEVICE_SYNAPTICS(DPAD, SYNUSB_TOUCHPAD) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, synusb_idtable);
|
||||
|
||||
static struct usb_driver synusb_driver = {
|
||||
.name = "synaptics_usb",
|
||||
.probe = synusb_probe,
|
||||
.disconnect = synusb_disconnect,
|
||||
.id_table = synusb_idtable,
|
||||
.suspend = synusb_suspend,
|
||||
.resume = synusb_resume,
|
||||
.pre_reset = synusb_pre_reset,
|
||||
.post_reset = synusb_post_reset,
|
||||
.reset_resume = synusb_reset_resume,
|
||||
.supports_autosuspend = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(synusb_driver);
|
||||
|
||||
MODULE_AUTHOR("Rob Miller <rob@inpharmatica.co.uk>, "
|
||||
"Ron Lee <ron@debian.org>, "
|
||||
"Jan Steinhoff <cpad@jan-steinhoff.de>");
|
||||
MODULE_DESCRIPTION("Synaptics USB device driver");
|
||||
MODULE_LICENSE("GPL");
|
87
drivers/input/of_keymap.c
Normal file
87
drivers/input/of_keymap.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Helpers for open firmware matrix keyboard bindings
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc
|
||||
*
|
||||
* Author:
|
||||
* Olof Johansson <olof@lixom.net>
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct matrix_keymap_data *
|
||||
matrix_keyboard_of_fill_keymap(struct device_node *np,
|
||||
const char *propname)
|
||||
{
|
||||
struct matrix_keymap_data *kd;
|
||||
u32 *keymap;
|
||||
int proplen, i;
|
||||
const __be32 *prop;
|
||||
|
||||
if (!np)
|
||||
return NULL;
|
||||
|
||||
if (!propname)
|
||||
propname = "linux,keymap";
|
||||
|
||||
prop = of_get_property(np, propname, &proplen);
|
||||
if (!prop)
|
||||
return NULL;
|
||||
|
||||
if (proplen % sizeof(u32)) {
|
||||
pr_warn("Malformed keymap property %s in %s\n",
|
||||
propname, np->full_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kd = kzalloc(sizeof(*kd), GFP_KERNEL);
|
||||
if (!kd)
|
||||
return NULL;
|
||||
|
||||
kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
|
||||
if (!kd->keymap) {
|
||||
kfree(kd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kd->keymap_size = proplen / sizeof(u32);
|
||||
|
||||
for (i = 0; i < kd->keymap_size; i++) {
|
||||
u32 tmp = be32_to_cpup(prop + i);
|
||||
int key_code, row, col;
|
||||
|
||||
row = (tmp >> 24) & 0xff;
|
||||
col = (tmp >> 16) & 0xff;
|
||||
key_code = tmp & 0xffff;
|
||||
keymap[i] = KEY(row, col, key_code);
|
||||
}
|
||||
|
||||
return kd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
|
||||
|
||||
void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
|
||||
{
|
||||
if (kd) {
|
||||
kfree(kd->keymap);
|
||||
kfree(kd);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);
|
|
@ -180,8 +180,6 @@ static const struct of_device_id altera_ps2_match[] = {
|
|||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, altera_ps2_match);
|
||||
#else /* CONFIG_OF */
|
||||
#define altera_ps2_match NULL
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
/*
|
||||
|
@ -193,7 +191,7 @@ static struct platform_driver altera_ps2_driver = {
|
|||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = altera_ps2_match,
|
||||
.of_match_table = of_match_ptr(altera_ps2_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(altera_ps2_driver);
|
||||
|
|
|
@ -98,9 +98,9 @@ struct psif {
|
|||
struct serio *io;
|
||||
void __iomem *regs;
|
||||
unsigned int irq;
|
||||
unsigned int open;
|
||||
/* Prevent concurrent writes to PSIF THR. */
|
||||
spinlock_t lock;
|
||||
bool open;
|
||||
};
|
||||
|
||||
static irqreturn_t psif_interrupt(int irq, void *_ptr)
|
||||
|
@ -164,7 +164,7 @@ static int psif_open(struct serio *io)
|
|||
psif_writel(psif, CR, PSIF_BIT(CR_TXEN) | PSIF_BIT(CR_RXEN));
|
||||
psif_writel(psif, IER, PSIF_BIT(RXRDY));
|
||||
|
||||
psif->open = 1;
|
||||
psif->open = true;
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ static void psif_close(struct serio *io)
|
|||
{
|
||||
struct psif *psif = io->port_data;
|
||||
|
||||
psif->open = 0;
|
||||
psif->open = false;
|
||||
|
||||
psif_writel(psif, IDR, ~0UL);
|
||||
psif_writel(psif, CR, PSIF_BIT(CR_TXDIS) | PSIF_BIT(CR_RXDIS));
|
||||
|
@ -319,9 +319,10 @@ static int __exit psif_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int psif_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int psif_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct psif *psif = platform_get_drvdata(pdev);
|
||||
|
||||
if (psif->open) {
|
||||
|
@ -332,8 +333,9 @@ static int psif_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int psif_resume(struct platform_device *pdev)
|
||||
static int psif_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct psif *psif = platform_get_drvdata(pdev);
|
||||
|
||||
if (psif->open) {
|
||||
|
@ -344,19 +346,17 @@ static int psif_resume(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define psif_suspend NULL
|
||||
#define psif_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(psif_pm_ops, psif_suspend, psif_resume);
|
||||
|
||||
static struct platform_driver psif_driver = {
|
||||
.remove = __exit_p(psif_remove),
|
||||
.driver = {
|
||||
.name = "atmel_psif",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &psif_pm_ops,
|
||||
},
|
||||
.suspend = psif_suspend,
|
||||
.resume = psif_resume,
|
||||
};
|
||||
|
||||
static int __init psif_init(void)
|
||||
|
|
|
@ -44,26 +44,31 @@
|
|||
#include <asm/irq.h>
|
||||
#include <asm/q40ints.h>
|
||||
|
||||
#define DRV_NAME "q40kbd"
|
||||
|
||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
|
||||
MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
||||
static DEFINE_SPINLOCK(q40kbd_lock);
|
||||
static struct serio *q40kbd_port;
|
||||
static struct platform_device *q40kbd_device;
|
||||
struct q40kbd {
|
||||
struct serio *port;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct q40kbd *q40kbd = dev_id;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&q40kbd_lock, flags);
|
||||
spin_lock_irqsave(&q40kbd->lock, flags);
|
||||
|
||||
if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
|
||||
serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
|
||||
serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0);
|
||||
|
||||
master_outb(-1, KEYBOARD_UNLOCK_REG);
|
||||
|
||||
spin_unlock_irqrestore(&q40kbd_lock, flags);
|
||||
spin_unlock_irqrestore(&q40kbd->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@ -72,17 +77,23 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
|
|||
* q40kbd_flush() flushes all data that may be in the keyboard buffers
|
||||
*/
|
||||
|
||||
static void q40kbd_flush(void)
|
||||
static void q40kbd_flush(struct q40kbd *q40kbd)
|
||||
{
|
||||
int maxread = 100;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&q40kbd_lock, flags);
|
||||
spin_lock_irqsave(&q40kbd->lock, flags);
|
||||
|
||||
while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
|
||||
master_inb(KEYCODE_REG);
|
||||
|
||||
spin_unlock_irqrestore(&q40kbd_lock, flags);
|
||||
spin_unlock_irqrestore(&q40kbd->lock, flags);
|
||||
}
|
||||
|
||||
static void q40kbd_stop(void)
|
||||
{
|
||||
master_outb(0, KEY_IRQ_ENABLE_REG);
|
||||
master_outb(-1, KEYBOARD_UNLOCK_REG);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -92,12 +103,9 @@ static void q40kbd_flush(void)
|
|||
|
||||
static int q40kbd_open(struct serio *port)
|
||||
{
|
||||
q40kbd_flush();
|
||||
struct q40kbd *q40kbd = port->port_data;
|
||||
|
||||
if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) {
|
||||
printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
|
||||
return -EBUSY;
|
||||
}
|
||||
q40kbd_flush(q40kbd);
|
||||
|
||||
/* off we go */
|
||||
master_outb(-1, KEYBOARD_UNLOCK_REG);
|
||||
|
@ -108,36 +116,72 @@ static int q40kbd_open(struct serio *port)
|
|||
|
||||
static void q40kbd_close(struct serio *port)
|
||||
{
|
||||
master_outb(0, KEY_IRQ_ENABLE_REG);
|
||||
master_outb(-1, KEYBOARD_UNLOCK_REG);
|
||||
free_irq(Q40_IRQ_KEYBOARD, NULL);
|
||||
struct q40kbd *q40kbd = port->port_data;
|
||||
|
||||
q40kbd_flush();
|
||||
q40kbd_stop();
|
||||
q40kbd_flush(q40kbd);
|
||||
}
|
||||
|
||||
static int __devinit q40kbd_probe(struct platform_device *dev)
|
||||
static int __devinit q40kbd_probe(struct platform_device *pdev)
|
||||
{
|
||||
q40kbd_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!q40kbd_port)
|
||||
return -ENOMEM;
|
||||
struct q40kbd *q40kbd;
|
||||
struct serio *port;
|
||||
int error;
|
||||
|
||||
q40kbd_port->id.type = SERIO_8042;
|
||||
q40kbd_port->open = q40kbd_open;
|
||||
q40kbd_port->close = q40kbd_close;
|
||||
q40kbd_port->dev.parent = &dev->dev;
|
||||
strlcpy(q40kbd_port->name, "Q40 Kbd Port", sizeof(q40kbd_port->name));
|
||||
strlcpy(q40kbd_port->phys, "Q40", sizeof(q40kbd_port->phys));
|
||||
q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL);
|
||||
port = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
if (!q40kbd || !port) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
serio_register_port(q40kbd_port);
|
||||
q40kbd->port = port;
|
||||
spin_lock_init(&q40kbd->lock);
|
||||
|
||||
port->id.type = SERIO_8042;
|
||||
port->open = q40kbd_open;
|
||||
port->close = q40kbd_close;
|
||||
port->port_data = q40kbd;
|
||||
port->dev.parent = &pdev->dev;
|
||||
strlcpy(port->name, "Q40 Kbd Port", sizeof(port->name));
|
||||
strlcpy(port->phys, "Q40", sizeof(port->phys));
|
||||
|
||||
q40kbd_stop();
|
||||
|
||||
error = request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0,
|
||||
DRV_NAME, q40kbd);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "Can't get irq %d.\n", Q40_IRQ_KEYBOARD);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
serio_register_port(q40kbd->port);
|
||||
|
||||
platform_set_drvdata(pdev, q40kbd);
|
||||
printk(KERN_INFO "serio: Q40 kbd registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_mem:
|
||||
kfree(port);
|
||||
kfree(q40kbd);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit q40kbd_remove(struct platform_device *dev)
|
||||
static int __devexit q40kbd_remove(struct platform_device *pdev)
|
||||
{
|
||||
serio_unregister_port(q40kbd_port);
|
||||
struct q40kbd *q40kbd = platform_get_drvdata(pdev);
|
||||
|
||||
/*
|
||||
* q40kbd_close() will be called as part of unregistering
|
||||
* and will ensure that IRQ is turned off, so it is safe
|
||||
* to unregister port first and free IRQ later.
|
||||
*/
|
||||
serio_unregister_port(q40kbd->port);
|
||||
free_irq(Q40_IRQ_KEYBOARD, q40kbd);
|
||||
kfree(q40kbd);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -146,41 +190,16 @@ static struct platform_driver q40kbd_driver = {
|
|||
.name = "q40kbd",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = q40kbd_probe,
|
||||
.remove = __devexit_p(q40kbd_remove),
|
||||
};
|
||||
|
||||
static int __init q40kbd_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!MACH_IS_Q40)
|
||||
return -ENODEV;
|
||||
|
||||
error = platform_driver_register(&q40kbd_driver);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
q40kbd_device = platform_device_alloc("q40kbd", -1);
|
||||
if (!q40kbd_device)
|
||||
goto err_unregister_driver;
|
||||
|
||||
error = platform_device_add(q40kbd_device);
|
||||
if (error)
|
||||
goto err_free_device;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_device:
|
||||
platform_device_put(q40kbd_device);
|
||||
err_unregister_driver:
|
||||
platform_driver_unregister(&q40kbd_driver);
|
||||
return error;
|
||||
return platform_driver_probe(&q40kbd_driver, q40kbd_probe);
|
||||
}
|
||||
|
||||
static void __exit q40kbd_exit(void)
|
||||
{
|
||||
platform_device_unregister(q40kbd_device);
|
||||
platform_driver_unregister(&q40kbd_driver);
|
||||
}
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ static int wacom_parse_logical_collection(unsigned char *report,
|
|||
|
||||
/* Logical collection is only used by 3rd gen Bamboo Touch */
|
||||
features->pktlen = WACOM_PKGLEN_BBTOUCH3;
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
features->device_type = BTN_TOOL_FINGER;
|
||||
|
||||
/*
|
||||
* Stylus and Touch have same active area
|
||||
|
@ -184,9 +184,9 @@ static int wacom_parse_logical_collection(unsigned char *report,
|
|||
* data before its overwritten.
|
||||
*/
|
||||
features->x_phy =
|
||||
(features->x_max * features->x_resolution) / 100;
|
||||
(features->x_max * 100) / features->x_resolution;
|
||||
features->y_phy =
|
||||
(features->y_max * features->y_resolution) / 100;
|
||||
(features->y_max * 100) / features->y_resolution;
|
||||
|
||||
features->x_max = features->y_max =
|
||||
get_unaligned_le16(&report[10]);
|
||||
|
@ -286,12 +286,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
|||
if (features->type == TABLETPC2FG) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_TPC2FG;
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
}
|
||||
if (features->type == BAMBOO_PT) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_BBTOUCH;
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
features->x_phy =
|
||||
get_unaligned_le16(&report[i + 5]);
|
||||
features->x_max =
|
||||
|
@ -325,7 +323,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
|||
if (features->type == TABLETPC2FG) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_TPC2FG;
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
features->y_max =
|
||||
get_unaligned_le16(&report[i + 3]);
|
||||
features->y_phy =
|
||||
|
@ -334,7 +331,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
|
|||
} else if (features->type == BAMBOO_PT) {
|
||||
/* need to reset back */
|
||||
features->pktlen = WACOM_PKGLEN_BBTOUCH;
|
||||
features->device_type = BTN_TOOL_DOUBLETAP;
|
||||
features->y_phy =
|
||||
get_unaligned_le16(&report[i + 3]);
|
||||
features->y_max =
|
||||
|
|
|
@ -832,12 +832,24 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
|
|||
|
||||
dbg("wacom_tpc_irq: received report #%d", data[0]);
|
||||
|
||||
if (len == WACOM_PKGLEN_TPC1FG || data[0] == WACOM_REPORT_TPC1FG)
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
else if (data[0] == WACOM_REPORT_TPC2FG)
|
||||
return wacom_tpc_mt_touch(wacom);
|
||||
else if (data[0] == WACOM_REPORT_PENABLED)
|
||||
return wacom_tpc_pen(wacom);
|
||||
switch (len) {
|
||||
case WACOM_PKGLEN_TPC1FG:
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_PKGLEN_TPC2FG:
|
||||
return wacom_tpc_mt_touch(wacom);
|
||||
|
||||
default:
|
||||
switch (data[0]) {
|
||||
case WACOM_REPORT_TPC1FG:
|
||||
case WACOM_REPORT_TPCHID:
|
||||
case WACOM_REPORT_TPCST:
|
||||
return wacom_tpc_single_touch(wacom, len);
|
||||
|
||||
case WACOM_REPORT_PENABLED:
|
||||
return wacom_tpc_pen(wacom);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1317,7 +1329,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
break;
|
||||
|
||||
case TABLETPC2FG:
|
||||
if (features->device_type == BTN_TOOL_DOUBLETAP) {
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
|
||||
input_mt_init_slots(input_dev, 2);
|
||||
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
|
||||
|
@ -1366,7 +1378,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
|
|||
|
||||
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
|
||||
|
||||
if (features->device_type == BTN_TOOL_DOUBLETAP) {
|
||||
if (features->device_type == BTN_TOOL_FINGER) {
|
||||
__set_bit(BTN_LEFT, input_dev->keybit);
|
||||
__set_bit(BTN_FORWARD, input_dev->keybit);
|
||||
__set_bit(BTN_BACK, input_dev->keybit);
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
#define WACOM_REPORT_INTUOSPAD 12
|
||||
#define WACOM_REPORT_TPC1FG 6
|
||||
#define WACOM_REPORT_TPC2FG 13
|
||||
#define WACOM_REPORT_TPCHID 15
|
||||
#define WACOM_REPORT_TPCST 16
|
||||
|
||||
/* device quirks */
|
||||
#define WACOM_QUIRK_MULTI_INPUT 0x0001
|
||||
|
|
|
@ -139,7 +139,6 @@ config TOUCHSCREEN_CY8CTMG110
|
|||
tristate "cy8ctmg110 touchscreen"
|
||||
depends on I2C
|
||||
depends on GPIOLIB
|
||||
|
||||
help
|
||||
Say Y here if you have a cy8ctmg110 capacitive touchscreen on
|
||||
an AAVA device.
|
||||
|
@ -149,6 +148,37 @@ config TOUCHSCREEN_CY8CTMG110
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called cy8ctmg110_ts.
|
||||
|
||||
config TOUCHSCREEN_CYTTSP_CORE
|
||||
tristate "Cypress TTSP touchscreen"
|
||||
help
|
||||
Say Y here if you have a touchscreen using controller from
|
||||
the Cypress TrueTouch(tm) Standard Product family connected
|
||||
to your system. You will also need to select appropriate
|
||||
bus connection below.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cyttsp_core.
|
||||
|
||||
config TOUCHSCREEN_CYTTSP_I2C
|
||||
tristate "support I2C bus connection"
|
||||
depends on TOUCHSCREEN_CYTTSP_CORE && I2C
|
||||
help
|
||||
Say Y here if the touchscreen is connected via I2C bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cyttsp_i2c.
|
||||
|
||||
config TOUCHSCREEN_CYTTSP_SPI
|
||||
tristate "support SPI bus connection"
|
||||
depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER
|
||||
help
|
||||
Say Y here if the touchscreen is connected via SPI bus.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cyttsp_spi.
|
||||
|
||||
config TOUCHSCREEN_DA9034
|
||||
tristate "Touchscreen support for Dialog Semiconductor DA9034"
|
||||
depends on PMIC_DA903X
|
||||
|
@ -213,6 +243,21 @@ config TOUCHSCREEN_FUJITSU
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called fujitsu-ts.
|
||||
|
||||
config TOUCHSCREEN_ILI210X
|
||||
tristate "Ilitek ILI210X based touchscreen"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have a ILI210X based touchscreen
|
||||
controller. This driver supports models ILI2102,
|
||||
ILI2102s, ILI2103, ILI2103s and ILI2105.
|
||||
Such kind of chipsets can be found in Amazon Kindle Fire
|
||||
touchscreens.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ili210x.
|
||||
|
||||
config TOUCHSCREEN_S3C2410
|
||||
tristate "Samsung S3C2410/generic touchscreen input driver"
|
||||
depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
|
||||
|
@ -430,6 +475,18 @@ config TOUCHSCREEN_TOUCHWIN
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called touchwin.
|
||||
|
||||
config TOUCHSCREEN_TI_TSCADC
|
||||
tristate "TI Touchscreen Interface"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
help
|
||||
Say Y here if you have 4/5/8 wire touchscreen controller
|
||||
to be connected to the ADC controller on your TI AM335x SoC.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ti_tscadc.
|
||||
|
||||
config TOUCHSCREEN_ATMEL_TSADCC
|
||||
tristate "Atmel Touchscreen Interface"
|
||||
depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
|
||||
|
@ -577,6 +634,7 @@ config TOUCHSCREEN_USB_COMPOSITE
|
|||
- JASTEC USB Touch Controller/DigiTech DTR-02U
|
||||
- Zytronic controllers
|
||||
- Elo TouchSystems 2700 IntelliTouch
|
||||
- EasyTouch USB Touch Controller from Data Modul
|
||||
|
||||
Have a look at <http://linux.chapter7.ch/touchkit/> for
|
||||
a usage description and the required user-space stuff.
|
||||
|
@ -681,6 +739,14 @@ config TOUCHSCREEN_USB_NEXIO
|
|||
bool "NEXIO/iNexio device support" if EXPERT
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
|
||||
config TOUCHSCREEN_USB_EASYTOUCH
|
||||
default y
|
||||
bool "EasyTouch USB Touch controller device support" if EMBEDDED
|
||||
depends on TOUCHSCREEN_USB_COMPOSITE
|
||||
help
|
||||
Say Y here if you have a EasyTouch USB Touch controller device support.
|
||||
If unsure, say N.
|
||||
|
||||
config TOUCHSCREEN_TOUCHIT213
|
||||
tristate "Sahara TouchIT-213 touchscreen"
|
||||
select SERIO
|
||||
|
|
|
@ -16,8 +16,11 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
|
||||
|
@ -26,6 +29,7 @@ obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
|
||||
|
@ -45,6 +49,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TI_TSCADC) += ti_tscadc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
|
|
|
@ -860,17 +860,7 @@ static struct spi_driver ad7877_driver = {
|
|||
.remove = __devexit_p(ad7877_remove),
|
||||
};
|
||||
|
||||
static int __init ad7877_init(void)
|
||||
{
|
||||
return spi_register_driver(&ad7877_driver);
|
||||
}
|
||||
module_init(ad7877_init);
|
||||
|
||||
static void __exit ad7877_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ad7877_driver);
|
||||
}
|
||||
module_exit(ad7877_exit);
|
||||
module_spi_driver(ad7877_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("AD7877 touchscreen Driver");
|
||||
|
|
|
@ -102,17 +102,7 @@ static struct i2c_driver ad7879_i2c_driver = {
|
|||
.id_table = ad7879_id,
|
||||
};
|
||||
|
||||
static int __init ad7879_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&ad7879_i2c_driver);
|
||||
}
|
||||
module_init(ad7879_i2c_init);
|
||||
|
||||
static void __exit ad7879_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&ad7879_i2c_driver);
|
||||
}
|
||||
module_exit(ad7879_i2c_exit);
|
||||
module_i2c_driver(ad7879_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver");
|
||||
|
|
|
@ -157,17 +157,7 @@ static struct spi_driver ad7879_spi_driver = {
|
|||
.remove = __devexit_p(ad7879_spi_remove),
|
||||
};
|
||||
|
||||
static int __init ad7879_spi_init(void)
|
||||
{
|
||||
return spi_register_driver(&ad7879_spi_driver);
|
||||
}
|
||||
module_init(ad7879_spi_init);
|
||||
|
||||
static void __exit ad7879_spi_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ad7879_spi_driver);
|
||||
}
|
||||
module_exit(ad7879_spi_exit);
|
||||
module_spi_driver(ad7879_spi_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
|
||||
MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver");
|
||||
|
|
|
@ -1433,17 +1433,7 @@ static struct spi_driver ads7846_driver = {
|
|||
.remove = __devexit_p(ads7846_remove),
|
||||
};
|
||||
|
||||
static int __init ads7846_init(void)
|
||||
{
|
||||
return spi_register_driver(&ads7846_driver);
|
||||
}
|
||||
module_init(ads7846_init);
|
||||
|
||||
static void __exit ads7846_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ads7846_driver);
|
||||
}
|
||||
module_exit(ads7846_exit);
|
||||
module_spi_driver(ads7846_driver);
|
||||
|
||||
MODULE_DESCRIPTION("ADS7846 TouchScreen Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -392,9 +392,10 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int atmel_wm97xx_suspend(struct *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
|
||||
|
||||
ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT);
|
||||
|
@ -404,8 +405,9 @@ static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_wm97xx_resume(struct platform_device *pdev)
|
||||
static int atmel_wm97xx_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev);
|
||||
struct wm97xx *wm = atmel_wm97xx->wm;
|
||||
|
||||
|
@ -416,18 +418,18 @@ static int atmel_wm97xx_resume(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define atmel_wm97xx_suspend NULL
|
||||
#define atmel_wm97xx_resume NULL
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(atmel_wm97xx_pm_ops,
|
||||
atmel_wm97xx_suspend, atmel_wm97xx_resume);
|
||||
|
||||
static struct platform_driver atmel_wm97xx_driver = {
|
||||
.remove = __exit_p(atmel_wm97xx_remove),
|
||||
.driver = {
|
||||
.name = "wm97xx-touch",
|
||||
.name = "wm97xx-touch",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &atmel_wm97xx_pm_ops,
|
||||
},
|
||||
.suspend = atmel_wm97xx_suspend,
|
||||
.resume = atmel_wm97xx_resume,
|
||||
};
|
||||
|
||||
static int __init atmel_wm97xx_init(void)
|
||||
|
|
|
@ -1267,18 +1267,7 @@ static struct i2c_driver mxt_driver = {
|
|||
.id_table = mxt_id,
|
||||
};
|
||||
|
||||
static int __init mxt_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mxt_driver);
|
||||
}
|
||||
|
||||
static void __exit mxt_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mxt_driver);
|
||||
}
|
||||
|
||||
module_init(mxt_init);
|
||||
module_exit(mxt_exit);
|
||||
module_i2c_driver(mxt_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
|
|
|
@ -635,17 +635,7 @@ static struct i2c_driver auo_pixcir_driver = {
|
|||
.id_table = auo_pixcir_idtable,
|
||||
};
|
||||
|
||||
static int __init auo_pixcir_init(void)
|
||||
{
|
||||
return i2c_add_driver(&auo_pixcir_driver);
|
||||
}
|
||||
module_init(auo_pixcir_init);
|
||||
|
||||
static void __exit auo_pixcir_exit(void)
|
||||
{
|
||||
i2c_del_driver(&auo_pixcir_driver);
|
||||
}
|
||||
module_exit(auo_pixcir_exit);
|
||||
module_i2c_driver(auo_pixcir_driver);
|
||||
|
||||
MODULE_DESCRIPTION("AUO-PIXCIR touchscreen driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -652,30 +652,7 @@ static struct i2c_driver bu21013_driver = {
|
|||
.id_table = bu21013_id,
|
||||
};
|
||||
|
||||
/**
|
||||
* bu21013_init() - initializes the bu21013 touchscreen driver
|
||||
*
|
||||
* This function used to initializes the bu21013
|
||||
* touchscreen driver and returns integer.
|
||||
*/
|
||||
static int __init bu21013_init(void)
|
||||
{
|
||||
return i2c_add_driver(&bu21013_driver);
|
||||
}
|
||||
|
||||
/**
|
||||
* bu21013_exit() - de-initializes the bu21013 touchscreen driver
|
||||
*
|
||||
* This function uses to de-initializes the bu21013
|
||||
* touchscreen driver and returns none.
|
||||
*/
|
||||
static void __exit bu21013_exit(void)
|
||||
{
|
||||
i2c_del_driver(&bu21013_driver);
|
||||
}
|
||||
|
||||
module_init(bu21013_init);
|
||||
module_exit(bu21013_exit);
|
||||
module_i2c_driver(bu21013_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
|
||||
|
|
|
@ -350,18 +350,7 @@ static struct i2c_driver cy8ctmg110_driver = {
|
|||
.remove = __devexit_p(cy8ctmg110_remove),
|
||||
};
|
||||
|
||||
static int __init cy8ctmg110_init(void)
|
||||
{
|
||||
return i2c_add_driver(&cy8ctmg110_driver);
|
||||
}
|
||||
|
||||
static void __exit cy8ctmg110_exit(void)
|
||||
{
|
||||
i2c_del_driver(&cy8ctmg110_driver);
|
||||
}
|
||||
|
||||
module_init(cy8ctmg110_init);
|
||||
module_exit(cy8ctmg110_exit);
|
||||
module_i2c_driver(cy8ctmg110_driver);
|
||||
|
||||
MODULE_AUTHOR("Samuli Konttila <samuli.konttila@aavamobile.com>");
|
||||
MODULE_DESCRIPTION("cy8ctmg110 TouchScreen Driver");
|
||||
|
|
625
drivers/input/touchscreen/cyttsp_core.c
Normal file
625
drivers/input/touchscreen/cyttsp_core.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* Core Source for:
|
||||
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
|
||||
* For use with Cypress Txx3xx parts.
|
||||
* Supported parts include:
|
||||
* CY8CTST341
|
||||
* CY8CTMA340
|
||||
*
|
||||
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, and only version 2, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "cyttsp_core.h"
|
||||
|
||||
/* Bootloader number of command keys */
|
||||
#define CY_NUM_BL_KEYS 8
|
||||
|
||||
/* helpers */
|
||||
#define GET_NUM_TOUCHES(x) ((x) & 0x0F)
|
||||
#define IS_LARGE_AREA(x) (((x) & 0x10) >> 4)
|
||||
#define IS_BAD_PKT(x) ((x) & 0x20)
|
||||
#define IS_VALID_APP(x) ((x) & 0x01)
|
||||
#define IS_OPERATIONAL_ERR(x) ((x) & 0x3F)
|
||||
#define GET_HSTMODE(reg) (((reg) & 0x70) >> 4)
|
||||
#define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
|
||||
|
||||
#define CY_REG_BASE 0x00
|
||||
#define CY_REG_ACT_DIST 0x1E
|
||||
#define CY_REG_ACT_INTRVL 0x1D
|
||||
#define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1)
|
||||
#define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1)
|
||||
#define CY_MAXZ 255
|
||||
#define CY_DELAY_DFLT 20 /* ms */
|
||||
#define CY_DELAY_MAX 500
|
||||
#define CY_ACT_DIST_DFLT 0xF8
|
||||
#define CY_HNDSHK_BIT 0x80
|
||||
/* device mode bits */
|
||||
#define CY_OPERATE_MODE 0x00
|
||||
#define CY_SYSINFO_MODE 0x10
|
||||
/* power mode select bits */
|
||||
#define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */
|
||||
#define CY_DEEP_SLEEP_MODE 0x02
|
||||
#define CY_LOW_POWER_MODE 0x04
|
||||
|
||||
/* Slots management */
|
||||
#define CY_MAX_FINGER 4
|
||||
#define CY_MAX_ID 16
|
||||
|
||||
static const u8 bl_command[] = {
|
||||
0x00, /* file offset */
|
||||
0xFF, /* command */
|
||||
0xA5, /* exit bootloader command */
|
||||
0, 1, 2, 3, 4, 5, 6, 7 /* default keys */
|
||||
};
|
||||
|
||||
static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
|
||||
u8 length, void *buf)
|
||||
{
|
||||
int error;
|
||||
int tries;
|
||||
|
||||
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
|
||||
error = ts->bus_ops->read(ts, command, length, buf);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
msleep(CY_DELAY_DFLT);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
|
||||
u8 length, void *buf)
|
||||
{
|
||||
int error;
|
||||
int tries;
|
||||
|
||||
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
|
||||
error = ts->bus_ops->write(ts, command, length, buf);
|
||||
if (!error)
|
||||
return 0;
|
||||
|
||||
msleep(CY_DELAY_DFLT);
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static int ttsp_send_command(struct cyttsp *ts, u8 cmd)
|
||||
{
|
||||
return ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
|
||||
}
|
||||
|
||||
static int cyttsp_load_bl_regs(struct cyttsp *ts)
|
||||
{
|
||||
memset(&ts->bl_data, 0, sizeof(ts->bl_data));
|
||||
ts->bl_data.bl_status = 0x10;
|
||||
|
||||
return ttsp_read_block_data(ts, CY_REG_BASE,
|
||||
sizeof(ts->bl_data), &ts->bl_data);
|
||||
}
|
||||
|
||||
static int cyttsp_exit_bl_mode(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
u8 bl_cmd[sizeof(bl_command)];
|
||||
|
||||
memcpy(bl_cmd, bl_command, sizeof(bl_command));
|
||||
if (ts->pdata->bl_keys)
|
||||
memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
|
||||
ts->pdata->bl_keys, sizeof(bl_command));
|
||||
|
||||
error = ttsp_write_block_data(ts, CY_REG_BASE,
|
||||
sizeof(bl_cmd), bl_cmd);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* wait for TTSP Device to complete the operation */
|
||||
msleep(CY_DELAY_DFLT);
|
||||
|
||||
error = cyttsp_load_bl_regs(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp_set_operational_mode(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ttsp_send_command(ts, CY_OPERATE_MODE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* wait for TTSP Device to complete switch to Operational mode */
|
||||
error = ttsp_read_block_data(ts, CY_REG_BASE,
|
||||
sizeof(ts->xy_data), &ts->xy_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return ts->xy_data.act_dist == CY_ACT_DIST_DFLT ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
memset(&ts->sysinfo_data, 0, sizeof(ts->sysinfo_data));
|
||||
|
||||
/* switch to sysinfo mode */
|
||||
error = ttsp_send_command(ts, CY_SYSINFO_MODE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* read sysinfo registers */
|
||||
msleep(CY_DELAY_DFLT);
|
||||
error = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
|
||||
&ts->sysinfo_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!ts->sysinfo_data.tts_verh && !ts->sysinfo_data.tts_verl)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (ts->pdata->act_intrvl != CY_ACT_INTRVL_DFLT ||
|
||||
ts->pdata->tch_tmout != CY_TCH_TMOUT_DFLT ||
|
||||
ts->pdata->lp_intrvl != CY_LP_INTRVL_DFLT) {
|
||||
|
||||
u8 intrvl_ray[] = {
|
||||
ts->pdata->act_intrvl,
|
||||
ts->pdata->tch_tmout,
|
||||
ts->pdata->lp_intrvl
|
||||
};
|
||||
|
||||
/* set intrvl registers */
|
||||
retval = ttsp_write_block_data(ts, CY_REG_ACT_INTRVL,
|
||||
sizeof(intrvl_ray), intrvl_ray);
|
||||
msleep(CY_DELAY_DFLT);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cyttsp_soft_reset(struct cyttsp *ts)
|
||||
{
|
||||
unsigned long timeout;
|
||||
int retval;
|
||||
|
||||
/* wait for interrupt to set ready completion */
|
||||
INIT_COMPLETION(ts->bl_ready);
|
||||
ts->state = CY_BL_STATE;
|
||||
|
||||
enable_irq(ts->irq);
|
||||
|
||||
retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
timeout = wait_for_completion_timeout(&ts->bl_ready,
|
||||
msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
|
||||
retval = timeout ? 0 : -EIO;
|
||||
|
||||
out:
|
||||
ts->state = CY_IDLE_STATE;
|
||||
disable_irq(ts->irq);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cyttsp_act_dist_setup(struct cyttsp *ts)
|
||||
{
|
||||
u8 act_dist_setup = ts->pdata->act_dist;
|
||||
|
||||
/* Init gesture; active distance setup */
|
||||
return ttsp_write_block_data(ts, CY_REG_ACT_DIST,
|
||||
sizeof(act_dist_setup), &act_dist_setup);
|
||||
}
|
||||
|
||||
static void cyttsp_extract_track_ids(struct cyttsp_xydata *xy_data, int *ids)
|
||||
{
|
||||
ids[0] = xy_data->touch12_id >> 4;
|
||||
ids[1] = xy_data->touch12_id & 0xF;
|
||||
ids[2] = xy_data->touch34_id >> 4;
|
||||
ids[3] = xy_data->touch34_id & 0xF;
|
||||
}
|
||||
|
||||
static const struct cyttsp_tch *cyttsp_get_tch(struct cyttsp_xydata *xy_data,
|
||||
int idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0:
|
||||
return &xy_data->tch1;
|
||||
case 1:
|
||||
return &xy_data->tch2;
|
||||
case 2:
|
||||
return &xy_data->tch3;
|
||||
case 3:
|
||||
return &xy_data->tch4;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void cyttsp_report_tchdata(struct cyttsp *ts)
|
||||
{
|
||||
struct cyttsp_xydata *xy_data = &ts->xy_data;
|
||||
struct input_dev *input = ts->input;
|
||||
int num_tch = GET_NUM_TOUCHES(xy_data->tt_stat);
|
||||
const struct cyttsp_tch *tch;
|
||||
int ids[CY_MAX_ID];
|
||||
int i;
|
||||
DECLARE_BITMAP(used, CY_MAX_ID);
|
||||
|
||||
if (IS_LARGE_AREA(xy_data->tt_stat) == 1) {
|
||||
/* terminate all active tracks */
|
||||
num_tch = 0;
|
||||
dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
|
||||
} else if (num_tch > CY_MAX_FINGER) {
|
||||
/* terminate all active tracks */
|
||||
num_tch = 0;
|
||||
dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
|
||||
} else if (IS_BAD_PKT(xy_data->tt_mode)) {
|
||||
/* terminate all active tracks */
|
||||
num_tch = 0;
|
||||
dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
|
||||
}
|
||||
|
||||
cyttsp_extract_track_ids(xy_data, ids);
|
||||
|
||||
bitmap_zero(used, CY_MAX_ID);
|
||||
|
||||
for (i = 0; i < num_tch; i++) {
|
||||
tch = cyttsp_get_tch(xy_data, i);
|
||||
|
||||
input_mt_slot(input, ids[i]);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
|
||||
input_report_abs(input, ABS_MT_POSITION_X, be16_to_cpu(tch->x));
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(tch->y));
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR, tch->z);
|
||||
|
||||
__set_bit(ids[i], used);
|
||||
}
|
||||
|
||||
for (i = 0; i < CY_MAX_ID; i++) {
|
||||
if (test_bit(i, used))
|
||||
continue;
|
||||
|
||||
input_mt_slot(input, i);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
|
||||
}
|
||||
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
static irqreturn_t cyttsp_irq(int irq, void *handle)
|
||||
{
|
||||
struct cyttsp *ts = handle;
|
||||
int error;
|
||||
|
||||
if (unlikely(ts->state == CY_BL_STATE)) {
|
||||
complete(&ts->bl_ready);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get touch data from CYTTSP device */
|
||||
error = ttsp_read_block_data(ts, CY_REG_BASE,
|
||||
sizeof(struct cyttsp_xydata), &ts->xy_data);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* provide flow control handshake */
|
||||
if (ts->pdata->use_hndshk) {
|
||||
error = ttsp_send_command(ts,
|
||||
ts->xy_data.hst_mode ^ CY_HNDSHK_BIT);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (unlikely(ts->state == CY_IDLE_STATE))
|
||||
goto out;
|
||||
|
||||
if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
|
||||
/*
|
||||
* TTSP device has reset back to bootloader mode.
|
||||
* Restore to operational mode.
|
||||
*/
|
||||
error = cyttsp_exit_bl_mode(ts);
|
||||
if (error) {
|
||||
dev_err(ts->dev,
|
||||
"Could not return to operational mode, err: %d\n",
|
||||
error);
|
||||
ts->state = CY_IDLE_STATE;
|
||||
}
|
||||
} else {
|
||||
cyttsp_report_tchdata(ts);
|
||||
}
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cyttsp_power_on(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = cyttsp_soft_reset(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = cyttsp_load_bl_regs(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
|
||||
IS_VALID_APP(ts->bl_data.bl_status)) {
|
||||
error = cyttsp_exit_bl_mode(ts);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (GET_HSTMODE(ts->bl_data.bl_file) != CY_OPERATE_MODE ||
|
||||
IS_OPERATIONAL_ERR(ts->bl_data.bl_status)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
error = cyttsp_set_sysinfo_mode(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = cyttsp_set_sysinfo_regs(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = cyttsp_set_operational_mode(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* init active distance */
|
||||
error = cyttsp_act_dist_setup(ts);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
ts->state = CY_ACTIVE_STATE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp_enable(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
/*
|
||||
* The device firmware can wake on an I2C or SPI memory slave
|
||||
* address match. So just reading a register is sufficient to
|
||||
* wake up the device. The first read attempt will fail but it
|
||||
* will wake it up making the second read attempt successful.
|
||||
*/
|
||||
error = ttsp_read_block_data(ts, CY_REG_BASE,
|
||||
sizeof(ts->xy_data), &ts->xy_data);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (GET_HSTMODE(ts->xy_data.hst_mode))
|
||||
return -EIO;
|
||||
|
||||
enable_irq(ts->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp_disable(struct cyttsp *ts)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ttsp_send_command(ts, CY_LOW_POWER_MODE);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
disable_irq(ts->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int cyttsp_suspend(struct device *dev)
|
||||
{
|
||||
struct cyttsp *ts = dev_get_drvdata(dev);
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&ts->input->mutex);
|
||||
|
||||
if (ts->input->users) {
|
||||
retval = cyttsp_disable(ts);
|
||||
if (retval == 0)
|
||||
ts->suspended = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cyttsp_resume(struct device *dev)
|
||||
{
|
||||
struct cyttsp *ts = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&ts->input->mutex);
|
||||
|
||||
if (ts->input->users)
|
||||
cyttsp_enable(ts);
|
||||
|
||||
ts->suspended = false;
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SIMPLE_DEV_PM_OPS(cyttsp_pm_ops, cyttsp_suspend, cyttsp_resume);
|
||||
EXPORT_SYMBOL_GPL(cyttsp_pm_ops);
|
||||
|
||||
static int cyttsp_open(struct input_dev *dev)
|
||||
{
|
||||
struct cyttsp *ts = input_get_drvdata(dev);
|
||||
int retval = 0;
|
||||
|
||||
if (!ts->suspended)
|
||||
retval = cyttsp_enable(ts);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void cyttsp_close(struct input_dev *dev)
|
||||
{
|
||||
struct cyttsp *ts = input_get_drvdata(dev);
|
||||
|
||||
if (!ts->suspended)
|
||||
cyttsp_disable(ts);
|
||||
}
|
||||
|
||||
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
|
||||
struct device *dev, int irq, size_t xfer_buf_size)
|
||||
{
|
||||
const struct cyttsp_platform_data *pdata = dev->platform_data;
|
||||
struct cyttsp *ts;
|
||||
struct input_dev *input_dev;
|
||||
int error;
|
||||
|
||||
if (!pdata || !pdata->name || irq <= 0) {
|
||||
error = -EINVAL;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ts = kzalloc(sizeof(*ts) + xfer_buf_size, GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ts || !input_dev) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
ts->dev = dev;
|
||||
ts->input = input_dev;
|
||||
ts->pdata = dev->platform_data;
|
||||
ts->bus_ops = bus_ops;
|
||||
ts->irq = irq;
|
||||
|
||||
init_completion(&ts->bl_ready);
|
||||
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
|
||||
|
||||
if (pdata->init) {
|
||||
error = pdata->init();
|
||||
if (error) {
|
||||
dev_err(ts->dev, "platform init failed, err: %d\n",
|
||||
error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
}
|
||||
|
||||
input_dev->name = pdata->name;
|
||||
input_dev->phys = ts->phys;
|
||||
input_dev->id.bustype = bus_ops->bustype;
|
||||
input_dev->dev.parent = ts->dev;
|
||||
|
||||
input_dev->open = cyttsp_open;
|
||||
input_dev->close = cyttsp_close;
|
||||
|
||||
input_set_drvdata(input_dev, ts);
|
||||
|
||||
__set_bit(EV_ABS, input_dev->evbit);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
|
||||
0, pdata->maxx, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
|
||||
0, pdata->maxy, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
|
||||
0, CY_MAXZ, 0, 0);
|
||||
|
||||
input_mt_init_slots(input_dev, CY_MAX_ID);
|
||||
|
||||
error = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
pdata->name, ts);
|
||||
if (error) {
|
||||
dev_err(ts->dev, "failed to request IRQ %d, err: %d\n",
|
||||
ts->irq, error);
|
||||
goto err_platform_exit;
|
||||
}
|
||||
|
||||
disable_irq(ts->irq);
|
||||
|
||||
error = cyttsp_power_on(ts);
|
||||
if (error)
|
||||
goto err_free_irq;
|
||||
|
||||
error = input_register_device(input_dev);
|
||||
if (error) {
|
||||
dev_err(ts->dev, "failed to register input device: %d\n",
|
||||
error);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
return ts;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(ts->irq, ts);
|
||||
err_platform_exit:
|
||||
if (pdata->exit)
|
||||
pdata->exit();
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ts);
|
||||
err_out:
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cyttsp_probe);
|
||||
|
||||
void cyttsp_remove(struct cyttsp *ts)
|
||||
{
|
||||
free_irq(ts->irq, ts);
|
||||
input_unregister_device(ts->input);
|
||||
if (ts->pdata->exit)
|
||||
ts->pdata->exit();
|
||||
kfree(ts);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cyttsp_remove);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
|
||||
MODULE_AUTHOR("Cypress");
|
149
drivers/input/touchscreen/cyttsp_core.h
Normal file
149
drivers/input/touchscreen/cyttsp_core.h
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* Header file for:
|
||||
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
|
||||
* For use with Cypress Txx3xx parts.
|
||||
* Supported parts include:
|
||||
* CY8CTST341
|
||||
* CY8CTMA340
|
||||
*
|
||||
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, and only version 2, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __CYTTSP_CORE_H__
|
||||
#define __CYTTSP_CORE_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/input/cyttsp.h>
|
||||
|
||||
#define CY_NUM_RETRY 16 /* max number of retries for read ops */
|
||||
|
||||
struct cyttsp_tch {
|
||||
__be16 x, y;
|
||||
u8 z;
|
||||
} __packed;
|
||||
|
||||
/* TrueTouch Standard Product Gen3 interface definition */
|
||||
struct cyttsp_xydata {
|
||||
u8 hst_mode;
|
||||
u8 tt_mode;
|
||||
u8 tt_stat;
|
||||
struct cyttsp_tch tch1;
|
||||
u8 touch12_id;
|
||||
struct cyttsp_tch tch2;
|
||||
u8 gest_cnt;
|
||||
u8 gest_id;
|
||||
struct cyttsp_tch tch3;
|
||||
u8 touch34_id;
|
||||
struct cyttsp_tch tch4;
|
||||
u8 tt_undef[3];
|
||||
u8 act_dist;
|
||||
u8 tt_reserved;
|
||||
} __packed;
|
||||
|
||||
|
||||
/* TTSP System Information interface definition */
|
||||
struct cyttsp_sysinfo_data {
|
||||
u8 hst_mode;
|
||||
u8 mfg_cmd;
|
||||
u8 mfg_stat;
|
||||
u8 cid[3];
|
||||
u8 tt_undef1;
|
||||
u8 uid[8];
|
||||
u8 bl_verh;
|
||||
u8 bl_verl;
|
||||
u8 tts_verh;
|
||||
u8 tts_verl;
|
||||
u8 app_idh;
|
||||
u8 app_idl;
|
||||
u8 app_verh;
|
||||
u8 app_verl;
|
||||
u8 tt_undef[5];
|
||||
u8 scn_typ;
|
||||
u8 act_intrvl;
|
||||
u8 tch_tmout;
|
||||
u8 lp_intrvl;
|
||||
};
|
||||
|
||||
/* TTSP Bootloader Register Map interface definition */
|
||||
#define CY_BL_CHKSUM_OK 0x01
|
||||
struct cyttsp_bootloader_data {
|
||||
u8 bl_file;
|
||||
u8 bl_status;
|
||||
u8 bl_error;
|
||||
u8 blver_hi;
|
||||
u8 blver_lo;
|
||||
u8 bld_blver_hi;
|
||||
u8 bld_blver_lo;
|
||||
u8 ttspver_hi;
|
||||
u8 ttspver_lo;
|
||||
u8 appid_hi;
|
||||
u8 appid_lo;
|
||||
u8 appver_hi;
|
||||
u8 appver_lo;
|
||||
u8 cid_0;
|
||||
u8 cid_1;
|
||||
u8 cid_2;
|
||||
};
|
||||
|
||||
struct cyttsp;
|
||||
|
||||
struct cyttsp_bus_ops {
|
||||
u16 bustype;
|
||||
int (*write)(struct cyttsp *ts,
|
||||
u8 addr, u8 length, const void *values);
|
||||
int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values);
|
||||
};
|
||||
|
||||
enum cyttsp_state {
|
||||
CY_IDLE_STATE,
|
||||
CY_ACTIVE_STATE,
|
||||
CY_BL_STATE,
|
||||
};
|
||||
|
||||
struct cyttsp {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
struct input_dev *input;
|
||||
char phys[32];
|
||||
const struct cyttsp_platform_data *pdata;
|
||||
const struct cyttsp_bus_ops *bus_ops;
|
||||
struct cyttsp_bootloader_data bl_data;
|
||||
struct cyttsp_sysinfo_data sysinfo_data;
|
||||
struct cyttsp_xydata xy_data;
|
||||
struct completion bl_ready;
|
||||
enum cyttsp_state state;
|
||||
bool suspended;
|
||||
|
||||
u8 xfer_buf[] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
|
||||
struct device *dev, int irq, size_t xfer_buf_size);
|
||||
void cyttsp_remove(struct cyttsp *ts);
|
||||
|
||||
extern const struct dev_pm_ops cyttsp_pm_ops;
|
||||
|
||||
#endif /* __CYTTSP_CORE_H__ */
|
136
drivers/input/touchscreen/cyttsp_i2c.c
Normal file
136
drivers/input/touchscreen/cyttsp_i2c.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Source for:
|
||||
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
|
||||
* For use with Cypress Txx3xx parts.
|
||||
* Supported parts include:
|
||||
* CY8CTST341
|
||||
* CY8CTMA340
|
||||
*
|
||||
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, and only version 2, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cyttsp_core.h"
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#define CY_I2C_DATA_SIZE 128
|
||||
|
||||
static int cyttsp_i2c_read_block_data(struct cyttsp *ts,
|
||||
u8 addr, u8 length, void *values)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(ts->dev);
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &addr,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = length,
|
||||
.buf = values,
|
||||
},
|
||||
};
|
||||
int retval;
|
||||
|
||||
retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int cyttsp_i2c_write_block_data(struct cyttsp *ts,
|
||||
u8 addr, u8 length, const void *values)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(ts->dev);
|
||||
int retval;
|
||||
|
||||
ts->xfer_buf[0] = addr;
|
||||
memcpy(&ts->xfer_buf[1], values, length);
|
||||
|
||||
retval = i2c_master_send(client, ts->xfer_buf, length + 1);
|
||||
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
|
||||
.bustype = BUS_I2C,
|
||||
.write = cyttsp_i2c_write_block_data,
|
||||
.read = cyttsp_i2c_read_block_data,
|
||||
};
|
||||
|
||||
static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct cyttsp *ts;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "I2C functionality not Supported\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ts = cyttsp_probe(&cyttsp_i2c_bus_ops, &client->dev, client->irq,
|
||||
CY_I2C_DATA_SIZE);
|
||||
|
||||
if (IS_ERR(ts))
|
||||
return PTR_ERR(ts);
|
||||
|
||||
i2c_set_clientdata(client, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct cyttsp *ts = i2c_get_clientdata(client);
|
||||
|
||||
cyttsp_remove(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cyttsp_i2c_id[] = {
|
||||
{ CY_I2C_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
|
||||
|
||||
static struct i2c_driver cyttsp_i2c_driver = {
|
||||
.driver = {
|
||||
.name = CY_I2C_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cyttsp_pm_ops,
|
||||
},
|
||||
.probe = cyttsp_i2c_probe,
|
||||
.remove = __devexit_p(cyttsp_i2c_remove),
|
||||
.id_table = cyttsp_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(cyttsp_i2c_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
|
||||
MODULE_AUTHOR("Cypress");
|
||||
MODULE_ALIAS("i2c:cyttsp");
|
200
drivers/input/touchscreen/cyttsp_spi.c
Normal file
200
drivers/input/touchscreen/cyttsp_spi.c
Normal file
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Source for:
|
||||
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
|
||||
* For use with Cypress Txx3xx parts.
|
||||
* Supported parts include:
|
||||
* CY8CTST341
|
||||
* CY8CTMA340
|
||||
*
|
||||
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, and only version 2, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cyttsp_core.h"
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define CY_SPI_WR_OP 0x00 /* r/~w */
|
||||
#define CY_SPI_RD_OP 0x01
|
||||
#define CY_SPI_CMD_BYTES 4
|
||||
#define CY_SPI_SYNC_BYTE 2
|
||||
#define CY_SPI_SYNC_ACK1 0x62 /* from protocol v.2 */
|
||||
#define CY_SPI_SYNC_ACK2 0x9D /* from protocol v.2 */
|
||||
#define CY_SPI_DATA_SIZE 128
|
||||
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
|
||||
#define CY_SPI_BITS_PER_WORD 8
|
||||
|
||||
static int cyttsp_spi_xfer(struct cyttsp *ts,
|
||||
u8 op, u8 reg, u8 *buf, int length)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(ts->dev);
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer[2];
|
||||
u8 *wr_buf = &ts->xfer_buf[0];
|
||||
u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE];
|
||||
int retval;
|
||||
int i;
|
||||
|
||||
if (length > CY_SPI_DATA_SIZE) {
|
||||
dev_err(ts->dev, "%s: length %d is too big.\n",
|
||||
__func__, length);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
|
||||
memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
|
||||
|
||||
wr_buf[0] = 0x00; /* header byte 0 */
|
||||
wr_buf[1] = 0xFF; /* header byte 1 */
|
||||
wr_buf[2] = reg; /* reg index */
|
||||
wr_buf[3] = op; /* r/~w */
|
||||
if (op == CY_SPI_WR_OP)
|
||||
memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
|
||||
|
||||
memset(xfer, 0, sizeof(xfer));
|
||||
spi_message_init(&msg);
|
||||
|
||||
/*
|
||||
We set both TX and RX buffers because Cypress TTSP
|
||||
requires full duplex operation.
|
||||
*/
|
||||
xfer[0].tx_buf = wr_buf;
|
||||
xfer[0].rx_buf = rd_buf;
|
||||
switch (op) {
|
||||
case CY_SPI_WR_OP:
|
||||
xfer[0].len = length + CY_SPI_CMD_BYTES;
|
||||
spi_message_add_tail(&xfer[0], &msg);
|
||||
break;
|
||||
|
||||
case CY_SPI_RD_OP:
|
||||
xfer[0].len = CY_SPI_CMD_BYTES;
|
||||
spi_message_add_tail(&xfer[0], &msg);
|
||||
|
||||
xfer[1].rx_buf = buf;
|
||||
xfer[1].len = length;
|
||||
spi_message_add_tail(&xfer[1], &msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = spi_sync(spi, &msg);
|
||||
if (retval < 0) {
|
||||
dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
|
||||
__func__, retval, xfer[1].len, op);
|
||||
|
||||
/*
|
||||
* do not return here since was a bad ACK sequence
|
||||
* let the following ACK check handle any errors and
|
||||
* allow silent retries
|
||||
*/
|
||||
}
|
||||
|
||||
if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
|
||||
rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
|
||||
|
||||
dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op);
|
||||
|
||||
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
|
||||
dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n",
|
||||
__func__, i, rd_buf[i]);
|
||||
for (i = 0; i < length; i++)
|
||||
dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n",
|
||||
__func__, i, buf[i]);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cyttsp_spi_read_block_data(struct cyttsp *ts,
|
||||
u8 addr, u8 length, void *data)
|
||||
{
|
||||
return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
|
||||
}
|
||||
|
||||
static int cyttsp_spi_write_block_data(struct cyttsp *ts,
|
||||
u8 addr, u8 length, const void *data)
|
||||
{
|
||||
return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
|
||||
}
|
||||
|
||||
static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
|
||||
.bustype = BUS_SPI,
|
||||
.write = cyttsp_spi_write_block_data,
|
||||
.read = cyttsp_spi_read_block_data,
|
||||
};
|
||||
|
||||
static int __devinit cyttsp_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct cyttsp *ts;
|
||||
int error;
|
||||
|
||||
/* Set up SPI*/
|
||||
spi->bits_per_word = CY_SPI_BITS_PER_WORD;
|
||||
spi->mode = SPI_MODE_0;
|
||||
error = spi_setup(spi);
|
||||
if (error < 0) {
|
||||
dev_err(&spi->dev, "%s: SPI setup error %d\n",
|
||||
__func__, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
ts = cyttsp_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
|
||||
CY_SPI_DATA_BUF_SIZE * 2);
|
||||
if (IS_ERR(ts))
|
||||
return PTR_ERR(ts);
|
||||
|
||||
spi_set_drvdata(spi, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit cyttsp_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct cyttsp *ts = spi_get_drvdata(spi);
|
||||
|
||||
cyttsp_remove(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver cyttsp_spi_driver = {
|
||||
.driver = {
|
||||
.name = CY_SPI_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cyttsp_pm_ops,
|
||||
},
|
||||
.probe = cyttsp_spi_probe,
|
||||
.remove = __devexit_p(cyttsp_spi_remove),
|
||||
};
|
||||
|
||||
module_spi_driver(cyttsp_spi_driver);
|
||||
|
||||
MODULE_ALIAS("spi:cyttsp");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
|
||||
MODULE_AUTHOR("Cypress");
|
||||
MODULE_ALIAS("spi:cyttsp");
|
|
@ -320,20 +320,8 @@ static struct i2c_driver eeti_ts_driver = {
|
|||
.id_table = eeti_ts_id,
|
||||
};
|
||||
|
||||
static int __init eeti_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&eeti_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit eeti_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&eeti_ts_driver);
|
||||
}
|
||||
module_i2c_driver(eeti_ts_driver);
|
||||
|
||||
MODULE_DESCRIPTION("EETI Touchscreen driver");
|
||||
MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(eeti_ts_init);
|
||||
module_exit(eeti_ts_exit);
|
||||
|
||||
|
|
|
@ -285,18 +285,7 @@ static struct i2c_driver egalax_ts_driver = {
|
|||
.remove = __devexit_p(egalax_ts_remove),
|
||||
};
|
||||
|
||||
static int __init egalax_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&egalax_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit egalax_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&egalax_ts_driver);
|
||||
}
|
||||
|
||||
module_init(egalax_ts_init);
|
||||
module_exit(egalax_ts_exit);
|
||||
module_i2c_driver(egalax_ts_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
||||
MODULE_DESCRIPTION("Touchscreen driver for EETI eGalax touch controller");
|
||||
|
|
|
@ -93,7 +93,7 @@ static int __init hp680_ts_init(void)
|
|||
hp680_ts_dev->phys = "hp680_ts/input0";
|
||||
|
||||
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
|
||||
0, MODNAME, 0) < 0) {
|
||||
0, MODNAME, NULL) < 0) {
|
||||
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
|
||||
HP680_TS_IRQ);
|
||||
err = -EBUSY;
|
||||
|
|
360
drivers/input/touchscreen/ili210x.c
Normal file
360
drivers/input/touchscreen/ili210x.c
Normal file
|
@ -0,0 +1,360 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/input/ili210x.h>
|
||||
|
||||
#define MAX_TOUCHES 2
|
||||
#define DEFAULT_POLL_PERIOD 20
|
||||
|
||||
/* Touchscreen commands */
|
||||
#define REG_TOUCHDATA 0x10
|
||||
#define REG_PANEL_INFO 0x20
|
||||
#define REG_FIRMWARE_VERSION 0x40
|
||||
#define REG_CALIBRATE 0xcc
|
||||
|
||||
struct finger {
|
||||
u8 x_low;
|
||||
u8 x_high;
|
||||
u8 y_low;
|
||||
u8 y_high;
|
||||
} __packed;
|
||||
|
||||
struct touchdata {
|
||||
u8 status;
|
||||
struct finger finger[MAX_TOUCHES];
|
||||
} __packed;
|
||||
|
||||
struct panel_info {
|
||||
struct finger finger_max;
|
||||
u8 xchannel_num;
|
||||
u8 ychannel_num;
|
||||
} __packed;
|
||||
|
||||
struct firmware_version {
|
||||
u8 id;
|
||||
u8 major;
|
||||
u8 minor;
|
||||
} __packed;
|
||||
|
||||
struct ili210x {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
bool (*get_pendown_state)(void);
|
||||
unsigned int poll_period;
|
||||
struct delayed_work dwork;
|
||||
};
|
||||
|
||||
static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct i2c_msg msg[2] = {
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = ®,
|
||||
},
|
||||
{
|
||||
.addr = client->addr,
|
||||
.flags = I2C_M_RD,
|
||||
.len = len,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
if (i2c_transfer(client->adapter, msg, 2) != 2) {
|
||||
dev_err(&client->dev, "i2c transfer failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ili210x_report_events(struct input_dev *input,
|
||||
const struct touchdata *touchdata)
|
||||
{
|
||||
int i;
|
||||
bool touch;
|
||||
unsigned int x, y;
|
||||
const struct finger *finger;
|
||||
|
||||
for (i = 0; i < MAX_TOUCHES; i++) {
|
||||
input_mt_slot(input, i);
|
||||
|
||||
finger = &touchdata->finger[i];
|
||||
|
||||
touch = touchdata->status & (1 << i);
|
||||
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
|
||||
if (touch) {
|
||||
x = finger->x_low | (finger->x_high << 8);
|
||||
y = finger->y_low | (finger->y_high << 8);
|
||||
|
||||
input_report_abs(input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(input, ABS_MT_POSITION_Y, y);
|
||||
}
|
||||
}
|
||||
|
||||
input_mt_report_pointer_emulation(input, false);
|
||||
input_sync(input);
|
||||
}
|
||||
|
||||
static bool get_pendown_state(const struct ili210x *priv)
|
||||
{
|
||||
bool state = false;
|
||||
|
||||
if (priv->get_pendown_state)
|
||||
state = priv->get_pendown_state();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void ili210x_work(struct work_struct *work)
|
||||
{
|
||||
struct ili210x *priv = container_of(work, struct ili210x,
|
||||
dwork.work);
|
||||
struct i2c_client *client = priv->client;
|
||||
struct touchdata touchdata;
|
||||
int error;
|
||||
|
||||
error = ili210x_read_reg(client, REG_TOUCHDATA,
|
||||
&touchdata, sizeof(touchdata));
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"Unable to get touchdata, err = %d\n", error);
|
||||
return;
|
||||
}
|
||||
|
||||
ili210x_report_events(priv->input, &touchdata);
|
||||
|
||||
if ((touchdata.status & 0xf3) || get_pendown_state(priv))
|
||||
schedule_delayed_work(&priv->dwork,
|
||||
msecs_to_jiffies(priv->poll_period));
|
||||
}
|
||||
|
||||
static irqreturn_t ili210x_irq(int irq, void *irq_data)
|
||||
{
|
||||
struct ili210x *priv = irq_data;
|
||||
|
||||
schedule_delayed_work(&priv->dwork, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static ssize_t ili210x_calibrate(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ili210x *priv = i2c_get_clientdata(client);
|
||||
unsigned long calibrate;
|
||||
int rc;
|
||||
u8 cmd = REG_CALIBRATE;
|
||||
|
||||
if (kstrtoul(buf, 10, &calibrate))
|
||||
return -EINVAL;
|
||||
|
||||
if (calibrate > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (calibrate) {
|
||||
rc = i2c_master_send(priv->client, &cmd, sizeof(cmd));
|
||||
if (rc != sizeof(cmd))
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate);
|
||||
|
||||
static struct attribute *ili210x_attributes[] = {
|
||||
&dev_attr_calibrate.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ili210x_attr_group = {
|
||||
.attrs = ili210x_attributes,
|
||||
};
|
||||
|
||||
static int __devinit ili210x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
const struct ili210x_platform_data *pdata = dev->platform_data;
|
||||
struct ili210x *priv;
|
||||
struct input_dev *input;
|
||||
struct panel_info panel;
|
||||
struct firmware_version firmware;
|
||||
int xmax, ymax;
|
||||
int error;
|
||||
|
||||
dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver");
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(dev, "No platform data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (client->irq <= 0) {
|
||||
dev_err(dev, "No IRQ!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get firmware version */
|
||||
error = ili210x_read_reg(client, REG_FIRMWARE_VERSION,
|
||||
&firmware, sizeof(firmware));
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to get firmware version, err: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* get panel info */
|
||||
error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to get panel informations, err: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
||||
xmax = panel.finger_max.x_low | (panel.finger_max.x_high << 8);
|
||||
ymax = panel.finger_max.y_low | (panel.finger_max.y_high << 8);
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!priv || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
priv->client = client;
|
||||
priv->input = input;
|
||||
priv->get_pendown_state = pdata->get_pendown_state;
|
||||
priv->poll_period = pdata->poll_period ? : DEFAULT_POLL_PERIOD;
|
||||
INIT_DELAYED_WORK(&priv->dwork, ili210x_work);
|
||||
|
||||
/* Setup input device */
|
||||
input->name = "ILI210x Touchscreen";
|
||||
input->id.bustype = BUS_I2C;
|
||||
input->dev.parent = dev;
|
||||
|
||||
__set_bit(EV_SYN, input->evbit);
|
||||
__set_bit(EV_KEY, input->evbit);
|
||||
__set_bit(EV_ABS, input->evbit);
|
||||
__set_bit(BTN_TOUCH, input->keybit);
|
||||
|
||||
/* Single touch */
|
||||
input_set_abs_params(input, ABS_X, 0, xmax, 0, 0);
|
||||
input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0);
|
||||
|
||||
/* Multi touch */
|
||||
input_mt_init_slots(input, MAX_TOUCHES);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0);
|
||||
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0);
|
||||
|
||||
input_set_drvdata(input, priv);
|
||||
i2c_set_clientdata(client, priv);
|
||||
|
||||
error = request_irq(client->irq, ili210x_irq, pdata->irq_flags,
|
||||
client->name, priv);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n",
|
||||
error);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = sysfs_create_group(&dev->kobj, &ili210x_attr_group);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to create sysfs attributes, err: %d\n",
|
||||
error);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
error = input_register_device(priv->input);
|
||||
if (error) {
|
||||
dev_err(dev, "Cannot regiser input device, err: %d\n", error);
|
||||
goto err_remove_sysfs;
|
||||
}
|
||||
|
||||
device_init_wakeup(&client->dev, 1);
|
||||
|
||||
dev_dbg(dev,
|
||||
"ILI210x initialized (IRQ: %d), firmware version %d.%d.%d",
|
||||
client->irq, firmware.id, firmware.major, firmware.minor);
|
||||
|
||||
return 0;
|
||||
|
||||
err_remove_sysfs:
|
||||
sysfs_remove_group(&dev->kobj, &ili210x_attr_group);
|
||||
err_free_irq:
|
||||
free_irq(client->irq, priv);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(priv);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit ili210x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ili210x *priv = i2c_get_clientdata(client);
|
||||
|
||||
sysfs_remove_group(&client->dev.kobj, &ili210x_attr_group);
|
||||
free_irq(priv->client->irq, priv);
|
||||
cancel_delayed_work_sync(&priv->dwork);
|
||||
input_unregister_device(priv->input);
|
||||
kfree(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int ili210x_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili210x_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (device_may_wakeup(&client->dev))
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm,
|
||||
ili210x_i2c_suspend, ili210x_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id ili210x_i2c_id[] = {
|
||||
{ "ili210x", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
|
||||
|
||||
static struct i2c_driver ili210x_ts_driver = {
|
||||
.driver = {
|
||||
.name = "ili210x_i2c",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &ili210x_i2c_pm,
|
||||
},
|
||||
.id_table = ili210x_i2c_id,
|
||||
.probe = ili210x_i2c_probe,
|
||||
.remove = __devexit_p(ili210x_i2c_remove),
|
||||
};
|
||||
|
||||
module_i2c_driver(ili210x_ts_driver);
|
||||
|
||||
MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
|
||||
MODULE_DESCRIPTION("ILI210X I2C Touchscreen Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -255,18 +255,7 @@ static struct i2c_driver max11801_ts_driver = {
|
|||
.remove = __devexit_p(max11801_ts_remove),
|
||||
};
|
||||
|
||||
static int __init max11801_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&max11801_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit max11801_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&max11801_ts_driver);
|
||||
}
|
||||
|
||||
module_init(max11801_ts_init);
|
||||
module_exit(max11801_ts_exit);
|
||||
module_i2c_driver(max11801_ts_driver);
|
||||
|
||||
MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
|
||||
MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
|
||||
|
|
|
@ -302,18 +302,7 @@ static struct i2c_driver mcs5000_ts_driver = {
|
|||
.id_table = mcs5000_ts_id,
|
||||
};
|
||||
|
||||
static int __init mcs5000_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&mcs5000_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit mcs5000_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&mcs5000_ts_driver);
|
||||
}
|
||||
|
||||
module_init(mcs5000_ts_init);
|
||||
module_exit(mcs5000_ts_exit);
|
||||
module_i2c_driver(mcs5000_ts_driver);
|
||||
|
||||
/* Module information */
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
|
|
|
@ -242,19 +242,8 @@ static struct i2c_driver migor_ts_driver = {
|
|||
.id_table = migor_ts_id,
|
||||
};
|
||||
|
||||
static int __init migor_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&migor_ts_driver);
|
||||
}
|
||||
|
||||
static void __exit migor_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&migor_ts_driver);
|
||||
}
|
||||
module_i2c_driver(migor_ts_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MigoR Touchscreen driver");
|
||||
MODULE_AUTHOR("Magnus Damm <damm@opensource.se>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(migor_ts_init);
|
||||
module_exit(migor_ts_exit);
|
||||
|
|
|
@ -222,17 +222,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = {
|
|||
.id_table = pixcir_i2c_ts_id,
|
||||
};
|
||||
|
||||
static int __init pixcir_i2c_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&pixcir_i2c_ts_driver);
|
||||
}
|
||||
module_init(pixcir_i2c_ts_init);
|
||||
|
||||
static void __exit pixcir_i2c_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&pixcir_i2c_ts_driver);
|
||||
}
|
||||
module_exit(pixcir_i2c_ts_exit);
|
||||
module_i2c_driver(pixcir_i2c_ts_driver);
|
||||
|
||||
MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>");
|
||||
MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver");
|
||||
|
|
|
@ -268,17 +268,7 @@ static struct i2c_driver st1232_ts_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init st1232_ts_init(void)
|
||||
{
|
||||
return i2c_add_driver(&st1232_ts_driver);
|
||||
}
|
||||
module_init(st1232_ts_init);
|
||||
|
||||
static void __exit st1232_ts_exit(void)
|
||||
{
|
||||
i2c_del_driver(&st1232_ts_driver);
|
||||
}
|
||||
module_exit(st1232_ts_exit);
|
||||
module_i2c_driver(st1232_ts_driver);
|
||||
|
||||
MODULE_AUTHOR("Tony SIM <chinyeow.sim.xt@renesas.com>");
|
||||
MODULE_DESCRIPTION("SITRONIX ST1232 Touchscreen Controller Driver");
|
||||
|
|
486
drivers/input/touchscreen/ti_tscadc.c
Normal file
486
drivers/input/touchscreen/ti_tscadc.c
Normal file
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* TI Touch Screen driver
|
||||
*
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/input/ti_tscadc.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define REG_IRQEOI 0x020
|
||||
#define REG_RAWIRQSTATUS 0x024
|
||||
#define REG_IRQSTATUS 0x028
|
||||
#define REG_IRQENABLE 0x02C
|
||||
#define REG_IRQWAKEUP 0x034
|
||||
#define REG_CTRL 0x040
|
||||
#define REG_ADCFSM 0x044
|
||||
#define REG_CLKDIV 0x04C
|
||||
#define REG_SE 0x054
|
||||
#define REG_IDLECONFIG 0x058
|
||||
#define REG_CHARGECONFIG 0x05C
|
||||
#define REG_CHARGEDELAY 0x060
|
||||
#define REG_STEPCONFIG(n) (0x64 + ((n - 1) * 8))
|
||||
#define REG_STEPDELAY(n) (0x68 + ((n - 1) * 8))
|
||||
#define REG_STEPCONFIG13 0x0C4
|
||||
#define REG_STEPDELAY13 0x0C8
|
||||
#define REG_STEPCONFIG14 0x0CC
|
||||
#define REG_STEPDELAY14 0x0D0
|
||||
#define REG_FIFO0CNT 0xE4
|
||||
#define REG_FIFO1THR 0xF4
|
||||
#define REG_FIFO0 0x100
|
||||
#define REG_FIFO1 0x200
|
||||
|
||||
/* Register Bitfields */
|
||||
#define IRQWKUP_ENB BIT(0)
|
||||
#define STPENB_STEPENB 0x7FFF
|
||||
#define IRQENB_FIFO1THRES BIT(5)
|
||||
#define IRQENB_PENUP BIT(9)
|
||||
#define STEPCONFIG_MODE_HWSYNC 0x2
|
||||
#define STEPCONFIG_SAMPLES_AVG (1 << 4)
|
||||
#define STEPCONFIG_XPP (1 << 5)
|
||||
#define STEPCONFIG_XNN (1 << 6)
|
||||
#define STEPCONFIG_YPP (1 << 7)
|
||||
#define STEPCONFIG_YNN (1 << 8)
|
||||
#define STEPCONFIG_XNP (1 << 9)
|
||||
#define STEPCONFIG_YPN (1 << 10)
|
||||
#define STEPCONFIG_INM (1 << 18)
|
||||
#define STEPCONFIG_INP (1 << 20)
|
||||
#define STEPCONFIG_INP_5 (1 << 21)
|
||||
#define STEPCONFIG_FIFO1 (1 << 26)
|
||||
#define STEPCONFIG_OPENDLY 0xff
|
||||
#define STEPCONFIG_Z1 (3 << 19)
|
||||
#define STEPIDLE_INP (1 << 22)
|
||||
#define STEPCHARGE_RFP (1 << 12)
|
||||
#define STEPCHARGE_INM (1 << 15)
|
||||
#define STEPCHARGE_INP (1 << 19)
|
||||
#define STEPCHARGE_RFM (1 << 23)
|
||||
#define STEPCHARGE_DELAY 0x1
|
||||
#define CNTRLREG_TSCSSENB (1 << 0)
|
||||
#define CNTRLREG_STEPID (1 << 1)
|
||||
#define CNTRLREG_STEPCONFIGWRT (1 << 2)
|
||||
#define CNTRLREG_4WIRE (1 << 5)
|
||||
#define CNTRLREG_5WIRE (1 << 6)
|
||||
#define CNTRLREG_8WIRE (3 << 5)
|
||||
#define CNTRLREG_TSCENB (1 << 7)
|
||||
#define ADCFSM_STEPID 0x10
|
||||
|
||||
#define SEQ_SETTLE 275
|
||||
#define ADC_CLK 3000000
|
||||
#define MAX_12BIT ((1 << 12) - 1)
|
||||
#define TSCADC_DELTA_X 15
|
||||
#define TSCADC_DELTA_Y 15
|
||||
|
||||
struct tscadc {
|
||||
struct input_dev *input;
|
||||
struct clk *tsc_ick;
|
||||
void __iomem *tsc_base;
|
||||
unsigned int irq;
|
||||
unsigned int wires;
|
||||
unsigned int x_plate_resistance;
|
||||
bool pen_down;
|
||||
};
|
||||
|
||||
static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
|
||||
{
|
||||
return readl(ts->tsc_base + reg);
|
||||
}
|
||||
|
||||
static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
|
||||
unsigned int val)
|
||||
{
|
||||
writel(val, tsc->tsc_base + reg);
|
||||
}
|
||||
|
||||
static void tscadc_step_config(struct tscadc *ts_dev)
|
||||
{
|
||||
unsigned int config;
|
||||
int i;
|
||||
|
||||
/* Configure the Step registers */
|
||||
|
||||
config = STEPCONFIG_MODE_HWSYNC |
|
||||
STEPCONFIG_SAMPLES_AVG | STEPCONFIG_XPP;
|
||||
switch (ts_dev->wires) {
|
||||
case 4:
|
||||
config |= STEPCONFIG_INP | STEPCONFIG_XNN;
|
||||
break;
|
||||
case 5:
|
||||
config |= STEPCONFIG_YNN |
|
||||
STEPCONFIG_INP_5 | STEPCONFIG_XNN |
|
||||
STEPCONFIG_YPP;
|
||||
break;
|
||||
case 8:
|
||||
config |= STEPCONFIG_INP | STEPCONFIG_XNN;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 1; i < 7; i++) {
|
||||
tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
|
||||
tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
|
||||
}
|
||||
|
||||
config = 0;
|
||||
config = STEPCONFIG_MODE_HWSYNC |
|
||||
STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YNN |
|
||||
STEPCONFIG_INM | STEPCONFIG_FIFO1;
|
||||
switch (ts_dev->wires) {
|
||||
case 4:
|
||||
config |= STEPCONFIG_YPP;
|
||||
break;
|
||||
case 5:
|
||||
config |= STEPCONFIG_XPP | STEPCONFIG_INP_5 |
|
||||
STEPCONFIG_XNP | STEPCONFIG_YPN;
|
||||
break;
|
||||
case 8:
|
||||
config |= STEPCONFIG_YPP;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 7; i < 13; i++) {
|
||||
tscadc_writel(ts_dev, REG_STEPCONFIG(i), config);
|
||||
tscadc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
|
||||
}
|
||||
|
||||
config = 0;
|
||||
/* Charge step configuration */
|
||||
config = STEPCONFIG_XPP | STEPCONFIG_YNN |
|
||||
STEPCHARGE_RFP | STEPCHARGE_RFM |
|
||||
STEPCHARGE_INM | STEPCHARGE_INP;
|
||||
|
||||
tscadc_writel(ts_dev, REG_CHARGECONFIG, config);
|
||||
tscadc_writel(ts_dev, REG_CHARGEDELAY, STEPCHARGE_DELAY);
|
||||
|
||||
config = 0;
|
||||
/* Configure to calculate pressure */
|
||||
config = STEPCONFIG_MODE_HWSYNC |
|
||||
STEPCONFIG_SAMPLES_AVG | STEPCONFIG_YPP |
|
||||
STEPCONFIG_XNN | STEPCONFIG_INM;
|
||||
tscadc_writel(ts_dev, REG_STEPCONFIG13, config);
|
||||
tscadc_writel(ts_dev, REG_STEPDELAY13, STEPCONFIG_OPENDLY);
|
||||
|
||||
config |= STEPCONFIG_Z1 | STEPCONFIG_FIFO1;
|
||||
tscadc_writel(ts_dev, REG_STEPCONFIG14, config);
|
||||
tscadc_writel(ts_dev, REG_STEPDELAY14, STEPCONFIG_OPENDLY);
|
||||
|
||||
tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
|
||||
}
|
||||
|
||||
static void tscadc_idle_config(struct tscadc *ts_config)
|
||||
{
|
||||
unsigned int idleconfig;
|
||||
|
||||
idleconfig = STEPCONFIG_YNN |
|
||||
STEPCONFIG_INM |
|
||||
STEPCONFIG_YPN | STEPIDLE_INP;
|
||||
tscadc_writel(ts_config, REG_IDLECONFIG, idleconfig);
|
||||
}
|
||||
|
||||
static void tscadc_read_coordinates(struct tscadc *ts_dev,
|
||||
unsigned int *x, unsigned int *y)
|
||||
{
|
||||
unsigned int fifocount = tscadc_readl(ts_dev, REG_FIFO0CNT);
|
||||
unsigned int prev_val_x = ~0, prev_val_y = ~0;
|
||||
unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
|
||||
unsigned int read, diff;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Delta filter is used to remove large variations in sampled
|
||||
* values from ADC. The filter tries to predict where the next
|
||||
* coordinate could be. This is done by taking a previous
|
||||
* coordinate and subtracting it form current one. Further the
|
||||
* algorithm compares the difference with that of a present value,
|
||||
* if true the value is reported to the sub system.
|
||||
*/
|
||||
for (i = 0; i < fifocount - 1; i++) {
|
||||
read = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
|
||||
diff = abs(read - prev_val_x);
|
||||
if (diff < prev_diff_x) {
|
||||
prev_diff_x = diff;
|
||||
*x = read;
|
||||
}
|
||||
prev_val_x = read;
|
||||
|
||||
read = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
|
||||
diff = abs(read - prev_val_y);
|
||||
if (diff < prev_diff_y) {
|
||||
prev_diff_y = diff;
|
||||
*y = read;
|
||||
}
|
||||
prev_val_y = read;
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t tscadc_irq(int irq, void *dev)
|
||||
{
|
||||
struct tscadc *ts_dev = dev;
|
||||
struct input_dev *input_dev = ts_dev->input;
|
||||
unsigned int status, irqclr = 0;
|
||||
unsigned int x = 0, y = 0;
|
||||
unsigned int z1, z2, z;
|
||||
unsigned int fsm;
|
||||
|
||||
status = tscadc_readl(ts_dev, REG_IRQSTATUS);
|
||||
if (status & IRQENB_FIFO1THRES) {
|
||||
tscadc_read_coordinates(ts_dev, &x, &y);
|
||||
|
||||
z1 = tscadc_readl(ts_dev, REG_FIFO0) & 0xfff;
|
||||
z2 = tscadc_readl(ts_dev, REG_FIFO1) & 0xfff;
|
||||
|
||||
if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
|
||||
/*
|
||||
* Calculate pressure using formula
|
||||
* Resistance(touch) = x plate resistance *
|
||||
* x postion/4096 * ((z2 / z1) - 1)
|
||||
*/
|
||||
z = z2 - z1;
|
||||
z *= x;
|
||||
z *= ts_dev->x_plate_resistance;
|
||||
z /= z1;
|
||||
z = (z + 2047) >> 12;
|
||||
|
||||
if (z <= MAX_12BIT) {
|
||||
input_report_abs(input_dev, ABS_X, x);
|
||||
input_report_abs(input_dev, ABS_Y, y);
|
||||
input_report_abs(input_dev, ABS_PRESSURE, z);
|
||||
input_report_key(input_dev, BTN_TOUCH, 1);
|
||||
input_sync(input_dev);
|
||||
}
|
||||
}
|
||||
irqclr |= IRQENB_FIFO1THRES;
|
||||
}
|
||||
|
||||
/*
|
||||
* Time for sequencer to settle, to read
|
||||
* correct state of the sequencer.
|
||||
*/
|
||||
udelay(SEQ_SETTLE);
|
||||
|
||||
status = tscadc_readl(ts_dev, REG_RAWIRQSTATUS);
|
||||
if (status & IRQENB_PENUP) {
|
||||
/* Pen up event */
|
||||
fsm = tscadc_readl(ts_dev, REG_ADCFSM);
|
||||
if (fsm == ADCFSM_STEPID) {
|
||||
ts_dev->pen_down = false;
|
||||
input_report_key(input_dev, BTN_TOUCH, 0);
|
||||
input_report_abs(input_dev, ABS_PRESSURE, 0);
|
||||
input_sync(input_dev);
|
||||
} else {
|
||||
ts_dev->pen_down = true;
|
||||
}
|
||||
irqclr |= IRQENB_PENUP;
|
||||
}
|
||||
|
||||
tscadc_writel(ts_dev, REG_IRQSTATUS, irqclr);
|
||||
/* check pending interrupts */
|
||||
tscadc_writel(ts_dev, REG_IRQEOI, 0x0);
|
||||
|
||||
tscadc_writel(ts_dev, REG_SE, STPENB_STEPENB);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* The functions for inserting/removing driver as a module.
|
||||
*/
|
||||
|
||||
static int __devinit tscadc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct tsc_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
struct tscadc *ts_dev;
|
||||
struct input_dev *input_dev;
|
||||
struct clk *clk;
|
||||
int err;
|
||||
int clk_value, ctrl, irq;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "missing platform data.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no memory resource defined.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq ID is specified.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allocate memory for device */
|
||||
ts_dev = kzalloc(sizeof(struct tscadc), GFP_KERNEL);
|
||||
input_dev = input_allocate_device();
|
||||
if (!ts_dev || !input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
ts_dev->input = input_dev;
|
||||
ts_dev->irq = irq;
|
||||
ts_dev->wires = pdata->wires;
|
||||
ts_dev->x_plate_resistance = pdata->x_plate_resistance;
|
||||
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "failed to reserve registers.\n");
|
||||
err = -EBUSY;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
ts_dev->tsc_base = ioremap(res->start, resource_size(res));
|
||||
if (!ts_dev->tsc_base) {
|
||||
dev_err(&pdev->dev, "failed to map registers.\n");
|
||||
err = -ENOMEM;
|
||||
goto err_release_mem_region;
|
||||
}
|
||||
|
||||
err = request_irq(ts_dev->irq, tscadc_irq,
|
||||
0, pdev->dev.driver->name, ts_dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "failed to allocate irq.\n");
|
||||
goto err_unmap_regs;
|
||||
}
|
||||
|
||||
ts_dev->tsc_ick = clk_get(&pdev->dev, "adc_tsc_ick");
|
||||
if (IS_ERR(ts_dev->tsc_ick)) {
|
||||
dev_err(&pdev->dev, "failed to get TSC ick\n");
|
||||
goto err_free_irq;
|
||||
}
|
||||
clk_enable(ts_dev->tsc_ick);
|
||||
|
||||
clk = clk_get(&pdev->dev, "adc_tsc_fck");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get TSC fck\n");
|
||||
err = PTR_ERR(clk);
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
clk_value = clk_get_rate(clk) / ADC_CLK;
|
||||
clk_put(clk);
|
||||
|
||||
if (clk_value < 7) {
|
||||
dev_err(&pdev->dev, "clock input less than min clock requirement\n");
|
||||
goto err_disable_clk;
|
||||
}
|
||||
/* CLKDIV needs to be configured to the value minus 1 */
|
||||
tscadc_writel(ts_dev, REG_CLKDIV, clk_value - 1);
|
||||
|
||||
/* Enable wake-up of the SoC using touchscreen */
|
||||
tscadc_writel(ts_dev, REG_IRQWAKEUP, IRQWKUP_ENB);
|
||||
|
||||
ctrl = CNTRLREG_STEPCONFIGWRT |
|
||||
CNTRLREG_TSCENB |
|
||||
CNTRLREG_STEPID;
|
||||
switch (ts_dev->wires) {
|
||||
case 4:
|
||||
ctrl |= CNTRLREG_4WIRE;
|
||||
break;
|
||||
case 5:
|
||||
ctrl |= CNTRLREG_5WIRE;
|
||||
break;
|
||||
case 8:
|
||||
ctrl |= CNTRLREG_8WIRE;
|
||||
break;
|
||||
}
|
||||
tscadc_writel(ts_dev, REG_CTRL, ctrl);
|
||||
|
||||
tscadc_idle_config(ts_dev);
|
||||
tscadc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO1THRES);
|
||||
tscadc_step_config(ts_dev);
|
||||
tscadc_writel(ts_dev, REG_FIFO1THR, 6);
|
||||
|
||||
ctrl |= CNTRLREG_TSCSSENB;
|
||||
tscadc_writel(ts_dev, REG_CTRL, ctrl);
|
||||
|
||||
input_dev->name = "ti-tsc-adc";
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
|
||||
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
|
||||
|
||||
/* register to the input system */
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
goto err_disable_clk;
|
||||
|
||||
platform_set_drvdata(pdev, ts_dev);
|
||||
return 0;
|
||||
|
||||
err_disable_clk:
|
||||
clk_disable(ts_dev->tsc_ick);
|
||||
clk_put(ts_dev->tsc_ick);
|
||||
err_free_irq:
|
||||
free_irq(ts_dev->irq, ts_dev);
|
||||
err_unmap_regs:
|
||||
iounmap(ts_dev->tsc_base);
|
||||
err_release_mem_region:
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
err_free_mem:
|
||||
input_free_device(input_dev);
|
||||
kfree(ts_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit tscadc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tscadc *ts_dev = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
free_irq(ts_dev->irq, ts_dev);
|
||||
|
||||
input_unregister_device(ts_dev->input);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
iounmap(ts_dev->tsc_base);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
clk_disable(ts_dev->tsc_ick);
|
||||
clk_put(ts_dev->tsc_ick);
|
||||
|
||||
kfree(ts_dev);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ti_tsc_driver = {
|
||||
.probe = tscadc_probe,
|
||||
.remove = __devexit_p(tscadc_remove),
|
||||
.driver = {
|
||||
.name = "tsc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
module_platform_driver(ti_tsc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TI touchscreen controller driver");
|
||||
MODULE_AUTHOR("Rachna Patil <rachna@ti.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -747,17 +747,7 @@ static struct spi_driver tsc2005_driver = {
|
|||
.remove = __devexit_p(tsc2005_remove),
|
||||
};
|
||||
|
||||
static int __init tsc2005_init(void)
|
||||
{
|
||||
return spi_register_driver(&tsc2005_driver);
|
||||
}
|
||||
module_init(tsc2005_init);
|
||||
|
||||
static void __exit tsc2005_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&tsc2005_driver);
|
||||
}
|
||||
module_exit(tsc2005_exit);
|
||||
module_spi_driver(tsc2005_driver);
|
||||
|
||||
MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
|
||||
MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
|
||||
|
|
|
@ -399,18 +399,7 @@ static struct i2c_driver tsc2007_driver = {
|
|||
.remove = __devexit_p(tsc2007_remove),
|
||||
};
|
||||
|
||||
static int __init tsc2007_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tsc2007_driver);
|
||||
}
|
||||
|
||||
static void __exit tsc2007_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tsc2007_driver);
|
||||
}
|
||||
|
||||
module_init(tsc2007_init);
|
||||
module_exit(tsc2007_exit);
|
||||
module_i2c_driver(tsc2007_driver);
|
||||
|
||||
MODULE_AUTHOR("Kwangwoo Lee <kwlee@mtekvision.com>");
|
||||
MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* - Zytronic capacitive touchscreen
|
||||
* - NEXIO/iNexio
|
||||
* - Elo TouchSystems 2700 IntelliTouch
|
||||
* - EasyTouch USB Dual/Multi touch controller from Data Modul
|
||||
*
|
||||
* Copyright (C) 2004-2007 by Daniel Ritz <daniel.ritz@gmx.ch>
|
||||
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||
|
@ -140,6 +141,7 @@ enum {
|
|||
DEVTYPE_TC45USB,
|
||||
DEVTYPE_NEXIO,
|
||||
DEVTYPE_ELO,
|
||||
DEVTYPE_ETOUCH,
|
||||
};
|
||||
|
||||
#define USB_DEVICE_HID_CLASS(vend, prod) \
|
||||
|
@ -245,6 +247,10 @@ static const struct usb_device_id usbtouch_devices[] = {
|
|||
{USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
|
||||
{USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
|
||||
#endif
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -326,6 +332,51 @@ static int egalax_get_pkt_len(unsigned char *buf, int len)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* EasyTouch part
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
|
||||
|
||||
#ifndef MULTI_PACKET
|
||||
#define MULTI_PACKET
|
||||
#endif
|
||||
|
||||
#define ETOUCH_PKT_TYPE_MASK 0xFE
|
||||
#define ETOUCH_PKT_TYPE_REPT 0x80
|
||||
#define ETOUCH_PKT_TYPE_REPT2 0xB0
|
||||
#define ETOUCH_PKT_TYPE_DIAG 0x0A
|
||||
|
||||
static int etouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
|
||||
{
|
||||
if ((pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT &&
|
||||
(pkt[0] & ETOUCH_PKT_TYPE_MASK) != ETOUCH_PKT_TYPE_REPT2)
|
||||
return 0;
|
||||
|
||||
dev->x = ((pkt[1] & 0x1F) << 7) | (pkt[2] & 0x7F);
|
||||
dev->y = ((pkt[3] & 0x1F) << 7) | (pkt[4] & 0x7F);
|
||||
dev->touch = pkt[0] & 0x01;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int etouch_get_pkt_len(unsigned char *buf, int len)
|
||||
{
|
||||
switch (buf[0] & ETOUCH_PKT_TYPE_MASK) {
|
||||
case ETOUCH_PKT_TYPE_REPT:
|
||||
case ETOUCH_PKT_TYPE_REPT2:
|
||||
return 5;
|
||||
|
||||
case ETOUCH_PKT_TYPE_DIAG:
|
||||
if (len < 2)
|
||||
return -1;
|
||||
|
||||
return buf[1] + 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* PanJit Part
|
||||
|
@ -1175,6 +1226,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
|
|||
.exit = nexio_exit,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
|
||||
[DEVTYPE_ETOUCH] = {
|
||||
.min_xc = 0x0,
|
||||
.max_xc = 0x07ff,
|
||||
.min_yc = 0x0,
|
||||
.max_yc = 0x07ff,
|
||||
.rept_size = 16,
|
||||
.process_pkt = usbtouch_process_multi,
|
||||
.get_pkt_len = etouch_get_pkt_len,
|
||||
.read_data = etouch_read_data,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -114,6 +114,31 @@ struct input_keymap_entry {
|
|||
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
|
||||
#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */
|
||||
|
||||
/**
|
||||
* EVIOCGMTSLOTS(len) - get MT slot values
|
||||
*
|
||||
* The ioctl buffer argument should be binary equivalent to
|
||||
*
|
||||
* struct input_mt_request_layout {
|
||||
* __u32 code;
|
||||
* __s32 values[num_slots];
|
||||
* };
|
||||
*
|
||||
* where num_slots is the (arbitrary) number of MT slots to extract.
|
||||
*
|
||||
* The ioctl size argument (len) is the size of the buffer, which
|
||||
* should satisfy len = (num_slots + 1) * sizeof(__s32). If len is
|
||||
* too small to fit all available slots, the first num_slots are
|
||||
* returned.
|
||||
*
|
||||
* Before the call, code is set to the wanted ABS_MT event type. On
|
||||
* return, values[] is filled with the slot values for the specified
|
||||
* ABS_MT code.
|
||||
*
|
||||
* If the request code is not an ABS_MT value, -EINVAL is returned.
|
||||
*/
|
||||
#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len)
|
||||
|
||||
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */
|
||||
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
|
||||
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
|
||||
|
@ -129,6 +154,8 @@ struct input_keymap_entry {
|
|||
|
||||
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
|
||||
|
||||
#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */
|
||||
|
||||
/*
|
||||
* Device properties and quirks
|
||||
*/
|
||||
|
|
58
include/linux/input/cyttsp.h
Normal file
58
include/linux/input/cyttsp.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Header file for:
|
||||
* Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
|
||||
* For use with Cypress Txx3xx parts.
|
||||
* Supported parts include:
|
||||
* CY8CTST341
|
||||
* CY8CTMA340
|
||||
*
|
||||
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2, and only version 2, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* 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.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
|
||||
*
|
||||
*/
|
||||
#ifndef _CYTTSP_H_
|
||||
#define _CYTTSP_H_
|
||||
|
||||
#define CY_SPI_NAME "cyttsp-spi"
|
||||
#define CY_I2C_NAME "cyttsp-i2c"
|
||||
/* Active Power state scanning/processing refresh interval */
|
||||
#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
|
||||
/* touch timeout for the Active power */
|
||||
#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
|
||||
/* Low Power state scanning/processing refresh interval */
|
||||
#define CY_LP_INTRVL_DFLT 0x0A /* ms */
|
||||
/* Active distance in pixels for a gesture to be reported */
|
||||
#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
|
||||
|
||||
struct cyttsp_platform_data {
|
||||
u32 maxx;
|
||||
u32 maxy;
|
||||
bool use_hndshk;
|
||||
u8 act_dist; /* Active distance */
|
||||
u8 act_intrvl; /* Active refresh interval; ms */
|
||||
u8 tch_tmout; /* Active touch timeout; ms */
|
||||
u8 lp_intrvl; /* Low power refresh interval; ms */
|
||||
int (*init)(void);
|
||||
void (*exit)(void);
|
||||
char *name;
|
||||
s16 irq_gpio;
|
||||
u8 *bl_keys;
|
||||
};
|
||||
|
||||
#endif /* _CYTTSP_H_ */
|
10
include/linux/input/ili210x.h
Normal file
10
include/linux/input/ili210x.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#ifndef _ILI210X_H
|
||||
#define _ILI210X_H
|
||||
|
||||
struct ili210x_platform_data {
|
||||
unsigned long irq_flags;
|
||||
unsigned int poll_period;
|
||||
bool (*get_pendown_state)(void);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
struct kxtj9_platform_data {
|
||||
unsigned int min_interval; /* minimum poll interval (in milli-seconds) */
|
||||
unsigned int init_interval; /* initial poll interval (in milli-seconds) */
|
||||
|
||||
/*
|
||||
* By default, x is axis 0, y is axis 1, z is axis 2; these can be
|
||||
|
@ -52,16 +53,6 @@ struct kxtj9_platform_data {
|
|||
#define KXTJ9_G_8G (1 << 4)
|
||||
u8 g_range;
|
||||
|
||||
/* DATA_CTRL_REG: controls the output data rate of the part */
|
||||
#define ODR12_5F 0
|
||||
#define ODR25F 1
|
||||
#define ODR50F 2
|
||||
#define ODR100F 3
|
||||
#define ODR200F 4
|
||||
#define ODR400F 5
|
||||
#define ODR800F 6
|
||||
u8 data_odr_init;
|
||||
|
||||
int (*init)(void);
|
||||
void (*exit)(void);
|
||||
int (*power_on)(void);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define MATRIX_MAX_ROWS 32
|
||||
#define MATRIX_MAX_COLS 32
|
||||
|
@ -106,4 +107,22 @@ matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
|
|||
__clear_bit(KEY_RESERVED, keybit);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_INPUT_OF_MATRIX_KEYMAP
|
||||
struct matrix_keymap_data *
|
||||
matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname);
|
||||
|
||||
void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd);
|
||||
#else
|
||||
static inline struct matrix_keymap_data *
|
||||
matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void
|
||||
matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MATRIX_KEYPAD_H */
|
||||
|
|
|
@ -48,10 +48,14 @@ static inline void input_mt_slot(struct input_dev *dev, int slot)
|
|||
input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
|
||||
}
|
||||
|
||||
static inline bool input_is_mt_value(int axis)
|
||||
{
|
||||
return axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST;
|
||||
}
|
||||
|
||||
static inline bool input_is_mt_axis(int axis)
|
||||
{
|
||||
return axis == ABS_MT_SLOT ||
|
||||
(axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST);
|
||||
return axis == ABS_MT_SLOT || input_is_mt_value(axis);
|
||||
}
|
||||
|
||||
void input_mt_report_slot_state(struct input_dev *dev,
|
||||
|
|
17
include/linux/input/ti_tscadc.h
Normal file
17
include/linux/input/ti_tscadc.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef __LINUX_TI_TSCADC_H
|
||||
#define __LINUX_TI_TSCADC_H
|
||||
|
||||
/**
|
||||
* struct tsc_data Touchscreen wire configuration
|
||||
* @wires: Wires refer to application modes
|
||||
* i.e. 4/5/8 wire touchscreen support
|
||||
* on the platform.
|
||||
* @x_plate_resistance: X plate resistance.
|
||||
*/
|
||||
|
||||
struct tsc_data {
|
||||
int wires;
|
||||
int x_plate_resistance;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -131,6 +131,55 @@ struct max8997_muic_platform_data {
|
|||
int num_init_data;
|
||||
};
|
||||
|
||||
enum max8997_haptic_motor_type {
|
||||
MAX8997_HAPTIC_ERM,
|
||||
MAX8997_HAPTIC_LRA,
|
||||
};
|
||||
|
||||
enum max8997_haptic_pulse_mode {
|
||||
MAX8997_EXTERNAL_MODE,
|
||||
MAX8997_INTERNAL_MODE,
|
||||
};
|
||||
|
||||
enum max8997_haptic_pwm_divisor {
|
||||
MAX8997_PWM_DIVISOR_32,
|
||||
MAX8997_PWM_DIVISOR_64,
|
||||
MAX8997_PWM_DIVISOR_128,
|
||||
MAX8997_PWM_DIVISOR_256,
|
||||
};
|
||||
|
||||
/**
|
||||
* max8997_haptic_platform_data
|
||||
* @pwm_channel_id: channel number of PWM device
|
||||
* valid for MAX8997_EXTERNAL_MODE
|
||||
* @pwm_period: period in nano second for PWM device
|
||||
* valid for MAX8997_EXTERNAL_MODE
|
||||
* @type: motor type
|
||||
* @mode: pulse mode
|
||||
* MAX8997_EXTERNAL_MODE: external PWM device is used to control motor
|
||||
* MAX8997_INTERNAL_MODE: internal pulse generator is used to control motor
|
||||
* @pwm_divisor: divisor for external PWM device
|
||||
* @internal_mode_pattern: internal mode pattern for internal mode
|
||||
* [0 - 3]: valid pattern number
|
||||
* @pattern_cycle: the number of cycles of the waveform
|
||||
* for the internal mode pattern
|
||||
* [0 - 15]: available cycles
|
||||
* @pattern_signal_period: period of the waveform for the internal mode pattern
|
||||
* [0 - 255]: available period
|
||||
*/
|
||||
struct max8997_haptic_platform_data {
|
||||
unsigned int pwm_channel_id;
|
||||
unsigned int pwm_period;
|
||||
|
||||
enum max8997_haptic_motor_type type;
|
||||
enum max8997_haptic_pulse_mode mode;
|
||||
enum max8997_haptic_pwm_divisor pwm_divisor;
|
||||
|
||||
unsigned int internal_mode_pattern;
|
||||
unsigned int pattern_cycle;
|
||||
unsigned int pattern_signal_period;
|
||||
};
|
||||
|
||||
enum max8997_led_mode {
|
||||
MAX8997_NONE,
|
||||
MAX8997_FLASH_MODE,
|
||||
|
@ -192,7 +241,9 @@ struct max8997_platform_data {
|
|||
/* ---- MUIC ---- */
|
||||
struct max8997_muic_platform_data *muic_pdata;
|
||||
|
||||
/* HAPTIC: Not implemented */
|
||||
/* ---- HAPTIC ---- */
|
||||
struct max8997_haptic_platform_data *haptic_pdata;
|
||||
|
||||
/* RTC: Not implemented */
|
||||
/* ---- LED ---- */
|
||||
struct max8997_led_platform_data *led_pdata;
|
||||
|
|
13
include/linux/platform_data/omap4-keypad.h
Normal file
13
include/linux/platform_data/omap4-keypad.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef __LINUX_INPUT_OMAP4_KEYPAD_H
|
||||
#define __LINUX_INPUT_OMAP4_KEYPAD_H
|
||||
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
struct omap4_keypad_platform_data {
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
|
||||
u8 rows;
|
||||
u8 cols;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_INPUT_OMAP4_KEYPAD_H */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue