Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:
 "First round of updates for the input subsystem.

  You will get a new touchsreen driver for Cypress 4th generation
  devices, a driver for a special controller implementing PS/2 protocol
  in OLPC devices, and a driver for power key for SiRFprimaII PWRC.

  HID and bcm5497 now support for the 2013 MacBook Air.

  EVIOCGKEY and the rest of evdev ioctls now flush events of matching
  type from the client's event queue so that clients can be sure any
  events received after issuing EVIOCG* ioctl are new events.

  And a host of cleanups and improvements in other drivers"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (87 commits)
  Input: cyttsp4 - kfree xfer_buf on error path in probe()
  Input: tps6507x-ts - select INPUT_POLLDEV
  Input: bcm5974 - add support for the 2013 MacBook Air
  HID: apple: Add support for the 2013 Macbook Air
  Input: cyttsp4 - leak on error path in probe()
  Input: cyttsp4 - silence NULL dereference warning
  Input: cyttsp4 - silence shift wrap warning
  Input: tps6507x-ts - convert to polled input device infrastructure
  ARM: davinci: da850-evm: remove vref from touchscreen platform data
  Input: cyttsp4 - SPI driver for Cypress TMA4XX touchscreen devices
  Input: cyttsp4 - I2C driver for Cypress TMA4XX touchscreen devices
  Input: cyttsp4 - add core driver for Cypress TMA4XX touchscreen devices
  Input: cyttsp - I2C driver split into two modules
  Input: add OLPC AP-SP driver
  Input: nspire-keypad - remove redundant dev_err call in nspire_keypad_probe()
  Input: tps6507x-ts - remove vref from platform data
  Input: tps6507x-ts - use bool for booleans
  Input: tps6507x-ts - remove bogus unreachable code
  Input: samsung-keypad - let device core setup the default pin configuration
  Input: wacom_i2c - implement hovering capability
  ...
This commit is contained in:
Linus Torvalds 2013-07-04 15:35:08 -07:00
commit f5b63ac0f7
105 changed files with 4795 additions and 514 deletions

View file

@ -0,0 +1,60 @@
* Marvell PXA Keypad controller
Required Properties
- compatible : should be "marvell,pxa27x-keypad"
- reg : Address and length of the register set for the device
- interrupts : The interrupt for the keypad controller
- marvell,debounce-interval : How long time the key will be
recognized when it is pressed. It is a u32 value, and bit[31:16]
is debounce interval for direct key and bit[15:0] is debounce
interval for matrix key. The value is in binary number of 2ms
Optional Properties For Matrix Keyes
Please refer to matrix-keymap.txt
Optional Properties for Direct Keyes
- marvell,direct-key-count : How many direct keyes are used.
- marvell,direct-key-mask : The mask indicates which keyes
are used. If bit[X] of the mask is set, the direct key X
is used.
- marvell,direct-key-low-active : Direct key status register
tells the level of pins that connects to the direct keyes.
When this property is set, it means that when the pin level
is low, the key is pressed(active).
- marvell,direct-key-map : It is a u16 array. Each item indicates
the linux key-code for the direct key.
Optional Properties For Rotary
- marvell,rotary0 : It is a u32 value. Bit[31:16] is the
linux key-code for rotary up. Bit[15:0] is the linux key-code
for rotary down. It is for rotary 0.
- marvell,rotary1 : Same as marvell,rotary0. It is for rotary 1.
- marvell,rotary-rel-key : When rotary is used for relative axes
in the device, the value indicates the key-code for relative
axes measurement in the device. It is a u32 value. Bit[31:16]
is for rotary 1, and Bit[15:0] is for rotary 0.
Examples:
keypad: keypad@d4012000 {
keypad,num-rows = <3>;
keypad,num-columns = <5>;
linux,keymap = <0x0000000e /* KEY_BACKSPACE */
0x0001006b /* KEY_END */
0x00020061 /* KEY_RIGHTCTRL */
0x0003000b /* KEY_0 */
0x00040002 /* KEY_1 */
0x0100008b /* KEY_MENU */
0x01010066 /* KEY_HOME */
0x010200e7 /* KEY_SEND */
0x01030009 /* KEY_8 */
0x0104000a /* KEY_9 */
0x02000160 /* KEY_OK */
0x02010003 /* KEY_2 */
0x02020004 /* KEY_3 */
0x02030005 /* KEY_4 */
0x02040006>; /* KEY_5 */
marvell,rotary0 = <0x006c0067>; /* KEY_UP & KEY_DOWN */
marvell,direct-key-count = <1>;
marvell,direct-key-map = <0x001c>;
marvell,debounce-interval = <0x001e001e>;
};

View file

@ -25,14 +25,6 @@ Required Board Specific Properties:
- samsung,keypad-num-columns: Number of column lines connected to the
keypad controller.
- row-gpios: List of gpios used as row lines. The gpio specifier for
this property depends on the gpio controller to which these row lines
are connected.
- col-gpios: List of gpios used as column lines. The gpio specifier for
this property depends on the gpio controller to which these column
lines are connected.
- Keys represented as child nodes: Each key connected to the keypad
controller is represented as a child node to the keypad controller
device node and should include the following properties.
@ -41,6 +33,9 @@ Required Board Specific Properties:
- linux,code: the key-code to be reported when the key is pressed
and released.
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Properties specific to linux:
- linux,keypad-no-autorepeat: do no enable autorepeat feature.
- linux,keypad-wakeup: use any event on keypad as wakeup event.
@ -56,17 +51,8 @@ Example:
linux,input-no-autorepeat;
linux,input-wakeup;
row-gpios = <&gpx2 0 3 3 0
&gpx2 1 3 3 0>;
col-gpios = <&gpx1 0 3 0 0
&gpx1 1 3 0 0
&gpx1 2 3 0 0
&gpx1 3 3 0 0
&gpx1 4 3 0 0
&gpx1 5 3 0 0
&gpx1 6 3 0 0
&gpx1 7 3 0 0>;
pinctrl-names = "default";
pinctrl-0 = <&keypad_rows &keypad_columns>;
key_1 {
keypad,row = <0>;

View file

@ -0,0 +1,60 @@
TI-NSPIRE Keypad
Required properties:
- compatible: Compatible property value should be "ti,nspire-keypad".
- reg: Physical base address of the peripheral and length of memory mapped
region.
- interrupts: The interrupt number for the peripheral.
- scan-interval: How often to scan in us. Based on a APB speed of 33MHz, the
maximum and minimum delay time is ~2000us and ~500us respectively
- row-delay: How long to wait before scanning each row.
- clocks: The clock this peripheral is attached to.
- linux,keymap: The keymap to use
(see Documentation/devicetree/bindings/input/matrix-keymap.txt)
Optional properties:
- active-low: Specify that the keypad is active low (i.e. logical low signifies
a key press).
Example:
input {
compatible = "ti,nspire-keypad";
reg = <0x900E0000 0x1000>;
interrupts = <16>;
scan-interval = <1000>;
row-delay = <200>;
clocks = <&apb_pclk>;
linux,keymap = <
0x0000001c 0x0001001c 0x00040039
0x0005002c 0x00060015 0x0007000b
0x0008000f 0x0100002d 0x01010011
0x0102002f 0x01030004 0x01040016
0x01050014 0x0106001f 0x01070002
0x010a006a 0x02000013 0x02010010
0x02020019 0x02030007 0x02040018
0x02050031 0x02060032 0x02070005
0x02080028 0x0209006c 0x03000026
0x03010025 0x03020024 0x0303000a
0x03040017 0x03050023 0x03060022
0x03070008 0x03080035 0x03090069
0x04000021 0x04010012 0x04020020
0x0404002e 0x04050030 0x0406001e
0x0407000d 0x04080037 0x04090067
0x05010038 0x0502000c 0x0503001b
0x05040034 0x0505001a 0x05060006
0x05080027 0x0509000e 0x050a006f
0x0600002b 0x0602004e 0x06030068
0x06040003 0x0605006d 0x06060009
0x06070001 0x0609000f 0x0708002a
0x0709001d 0x070a0033 >;
};

View file

@ -0,0 +1,13 @@
OLPC AP-SP serio interface
Required properties:
- compatible : "olpc,ap-sp"
- reg : base address and length of SoC's WTM registers
- interrupts : SP-AP interrupt
Example:
ap-sp@d4290000 {
compatible = "olpc,ap-sp";
reg = <0xd4290000 0x1000>;
interrupts = <40>;
}

View file

@ -80,6 +80,8 @@ Userspace can detect that a driver can report more total contacts than slots
by noting that the largest supported BTN_TOOL_*TAP event is larger than the
total number of type B slots reported in the absinfo for the ABS_MT_SLOT axis.
The minimum value of the ABS_MT_SLOT axis must be 0.
Protocol Example A
------------------

View file

@ -985,7 +985,6 @@ static struct regulator_init_data tps65070_regulator_data[] = {
static struct touchscreen_init_data tps6507x_touchscreen_data = {
.poll_period = 30, /* ms between touch samples */
.min_pressure = 0x30, /* minimum pressure to trigger touch */
.vref = 0, /* turn off vref when not using A/D */
.vendor = 0, /* /sys/class/input/input?/id/vendor */
.product = 65070, /* /sys/class/input/input?/id/product */
.version = 0x100, /* /sys/class/input/input?/id/version */

View file

@ -210,7 +210,7 @@ struct pxa168fb_mach_info aspenite_lcd_info = {
.invert_pixclock = 0,
};
static unsigned int aspenite_matrix_key_map[] = {
static const unsigned int aspenite_matrix_key_map[] = {
KEY(0, 6, KEY_UP), /* SW 4 */
KEY(0, 7, KEY_DOWN), /* SW 5 */
KEY(1, 6, KEY_LEFT), /* SW 6 */
@ -219,11 +219,15 @@ static unsigned int aspenite_matrix_key_map[] = {
KEY(4, 7, KEY_ESC), /* SW 9 */
};
static struct matrix_keymap_data aspenite_matrix_keymap_data = {
.keymap = aspenite_matrix_key_map,
.keymap_size = ARRAY_SIZE(aspenite_matrix_key_map),
};
static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
.matrix_key_rows = 5,
.matrix_key_cols = 8,
.matrix_key_map = aspenite_matrix_key_map,
.matrix_key_map_size = ARRAY_SIZE(aspenite_matrix_key_map),
.matrix_keymap_data = &aspenite_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -61,11 +61,15 @@ static unsigned int teton_bga_matrix_key_map[] = {
KEY(1, 7, KEY_RIGHT),
};
static struct matrix_keymap_data teton_bga_matrix_keymap_data = {
.keymap = teton_bga_matrix_key_map,
.keymap_size = ARRAY_SIZE(teton_bga_matrix_key_map),
};
static struct pxa27x_keypad_platform_data teton_bga_keypad_info __initdata = {
.matrix_key_rows = 2,
.matrix_key_cols = 8,
.matrix_key_map = teton_bga_matrix_key_map,
.matrix_key_map_size = ARRAY_SIZE(teton_bga_matrix_key_map),
.matrix_keymap_data = &teton_bga_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -833,21 +833,25 @@ static inline void em_x270_init_ac97(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int em_x270_module_matrix_keys[] = {
static const unsigned int em_x270_module_matrix_keys[] = {
KEY(0, 0, KEY_A), KEY(1, 0, KEY_UP), KEY(2, 1, KEY_B),
KEY(0, 2, KEY_LEFT), KEY(1, 1, KEY_ENTER), KEY(2, 0, KEY_RIGHT),
KEY(0, 1, KEY_C), KEY(1, 2, KEY_DOWN), KEY(2, 2, KEY_D),
};
static struct matrix_keymap_data em_x270_matrix_keymap_data = {
.keymap = em_x270_module_matrix_keys,
.keymap_size = ARRAY_SIZE(em_x270_module_matrix_keys),
};
struct pxa27x_keypad_platform_data em_x270_module_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 3,
.matrix_key_cols = 3,
.matrix_key_map = em_x270_module_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(em_x270_module_matrix_keys),
.matrix_keymap_data = &em_x270_matrix_keymap_data,
};
static unsigned int em_x270_exeda_matrix_keys[] = {
static const unsigned int em_x270_exeda_matrix_keys[] = {
KEY(0, 0, KEY_RIGHTSHIFT), KEY(0, 1, KEY_RIGHTCTRL),
KEY(0, 2, KEY_RIGHTALT), KEY(0, 3, KEY_SPACE),
KEY(0, 4, KEY_LEFTALT), KEY(0, 5, KEY_LEFTCTRL),
@ -889,12 +893,16 @@ static unsigned int em_x270_exeda_matrix_keys[] = {
KEY(7, 6, 0), KEY(7, 7, 0),
};
static struct matrix_keymap_data em_x270_exeda_matrix_keymap_data = {
.keymap = em_x270_exeda_matrix_keys,
.keymap_size = ARRAY_SIZE(em_x270_exeda_matrix_keys),
};
struct pxa27x_keypad_platform_data em_x270_exeda_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 8,
.matrix_key_cols = 8,
.matrix_key_map = em_x270_exeda_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(em_x270_exeda_matrix_keys),
.matrix_keymap_data = &em_x270_exeda_matrix_keymap_data,
};
static void __init em_x270_init_keypad(void)

View file

@ -392,7 +392,7 @@ static unsigned long e6_pin_config[] __initdata = {
/* KEYPAD */
#ifdef CONFIG_MACH_EZX_A780
static unsigned int a780_key_map[] = {
static const unsigned int a780_key_map[] = {
KEY(0, 0, KEY_SEND),
KEY(0, 1, KEY_BACK),
KEY(0, 2, KEY_END),
@ -424,11 +424,15 @@ static unsigned int a780_key_map[] = {
KEY(4, 4, KEY_DOWN),
};
static struct matrix_keymap_data a780_matrix_keymap_data = {
.keymap = a780_key_map,
.keymap_size = ARRAY_SIZE(a780_key_map),
};
static struct pxa27x_keypad_platform_data a780_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 5,
.matrix_key_map = a780_key_map,
.matrix_key_map_size = ARRAY_SIZE(a780_key_map),
.matrix_keymap_data = &a780_matrix_keymap_data,
.direct_key_map = { KEY_CAMERA },
.direct_key_num = 1,
@ -438,7 +442,7 @@ static struct pxa27x_keypad_platform_data a780_keypad_platform_data = {
#endif /* CONFIG_MACH_EZX_A780 */
#ifdef CONFIG_MACH_EZX_E680
static unsigned int e680_key_map[] = {
static const unsigned int e680_key_map[] = {
KEY(0, 0, KEY_UP),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_RESERVED),
@ -455,11 +459,15 @@ static unsigned int e680_key_map[] = {
KEY(2, 3, KEY_KPENTER),
};
static struct matrix_keymap_data e680_matrix_keymap_data = {
.keymap = e680_key_map,
.keymap_size = ARRAY_SIZE(e680_key_map),
};
static struct pxa27x_keypad_platform_data e680_keypad_platform_data = {
.matrix_key_rows = 3,
.matrix_key_cols = 4,
.matrix_key_map = e680_key_map,
.matrix_key_map_size = ARRAY_SIZE(e680_key_map),
.matrix_keymap_data = &e680_matrix_keymap_data,
.direct_key_map = {
KEY_CAMERA,
@ -476,7 +484,7 @@ static struct pxa27x_keypad_platform_data e680_keypad_platform_data = {
#endif /* CONFIG_MACH_EZX_E680 */
#ifdef CONFIG_MACH_EZX_A1200
static unsigned int a1200_key_map[] = {
static const unsigned int a1200_key_map[] = {
KEY(0, 0, KEY_RESERVED),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@ -513,18 +521,22 @@ static unsigned int a1200_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
static struct matrix_keymap_data a1200_matrix_keymap_data = {
.keymap = a1200_key_map,
.keymap_size = ARRAY_SIZE(a1200_key_map),
};
static struct pxa27x_keypad_platform_data a1200_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
.matrix_key_map = a1200_key_map,
.matrix_key_map_size = ARRAY_SIZE(a1200_key_map),
.matrix_keymap_data = &a1200_matrix_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_A1200 */
#ifdef CONFIG_MACH_EZX_E6
static unsigned int e6_key_map[] = {
static const unsigned int e6_key_map[] = {
KEY(0, 0, KEY_RESERVED),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@ -561,18 +573,22 @@ static unsigned int e6_key_map[] = {
KEY(4, 5, KEY_PREVIOUSSONG),
};
static struct matrix_keymap_data e6_keymap_data = {
.keymap = e6_key_map,
.keymap_size = ARRAY_SIZE(e6_key_map),
};
static struct pxa27x_keypad_platform_data e6_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
.matrix_key_map = e6_key_map,
.matrix_key_map_size = ARRAY_SIZE(e6_key_map),
.matrix_keymap_data = &e6_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_E6 */
#ifdef CONFIG_MACH_EZX_A910
static unsigned int a910_key_map[] = {
static const unsigned int a910_key_map[] = {
KEY(0, 0, KEY_NUMERIC_6),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@ -609,18 +625,22 @@ static unsigned int a910_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
static struct matrix_keymap_data a910_matrix_keymap_data = {
.keymap = a910_key_map,
.keymap_size = ARRAY_SIZE(a910_key_map),
};
static struct pxa27x_keypad_platform_data a910_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
.matrix_key_map = a910_key_map,
.matrix_key_map_size = ARRAY_SIZE(a910_key_map),
.matrix_keymap_data = &a910_matrix_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_A910 */
#ifdef CONFIG_MACH_EZX_E2
static unsigned int e2_key_map[] = {
static const unsigned int e2_key_map[] = {
KEY(0, 0, KEY_NUMERIC_6),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_NUMERIC_9),
@ -657,11 +677,15 @@ static unsigned int e2_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
static struct matrix_keymap_data e2_matrix_keymap_data = {
.keymap = e2_key_map,
.keymap_size = ARRAY_SIZE(e2_key_map),
};
static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
.matrix_key_map = e2_key_map,
.matrix_key_map_size = ARRAY_SIZE(e2_key_map),
.matrix_keymap_data = &e2_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -222,7 +222,7 @@ static inline void littleton_init_spi(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int littleton_matrix_key_map[] = {
static const unsigned int littleton_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(1, 3, KEY_0), KEY(0, 0, KEY_1), KEY(1, 0, KEY_2), KEY(2, 0, KEY_3),
KEY(0, 1, KEY_4), KEY(1, 1, KEY_5), KEY(2, 1, KEY_6), KEY(0, 2, KEY_7),
@ -249,11 +249,15 @@ static unsigned int littleton_matrix_key_map[] = {
KEY(3, 1, KEY_F23), /* soft2 */
};
static struct matrix_keymap_data littleton_matrix_keymap_data = {
.keymap = littleton_matrix_key_map,
.keymap_size = ARRAY_SIZE(littleton_matrix_key_map),
};
static struct pxa27x_keypad_platform_data littleton_keypad_info = {
.matrix_key_rows = 6,
.matrix_key_cols = 5,
.matrix_key_map = littleton_matrix_key_map,
.matrix_key_map_size = ARRAY_SIZE(littleton_matrix_key_map),
.matrix_keymap_data = &littleton_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,

View file

@ -498,7 +498,7 @@ static struct pxaohci_platform_data mainstone_ohci_platform_data = {
};
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int mainstone_matrix_keys[] = {
static const unsigned int mainstone_matrix_keys[] = {
KEY(0, 0, KEY_A), KEY(1, 0, KEY_B), KEY(2, 0, KEY_C),
KEY(3, 0, KEY_D), KEY(4, 0, KEY_E), KEY(5, 0, KEY_F),
KEY(0, 1, KEY_G), KEY(1, 1, KEY_H), KEY(2, 1, KEY_I),
@ -527,11 +527,15 @@ static unsigned int mainstone_matrix_keys[] = {
KEY(4, 6, KEY_SELECT),
};
static struct matrix_keymap_data mainstone_matrix_keymap_data = {
.keymap = mainstone_matrix_keys,
.keymap_size = ARRAY_SIZE(mainstone_matrix_keys),
};
struct pxa27x_keypad_platform_data mainstone_keypad_info = {
.matrix_key_rows = 6,
.matrix_key_cols = 7,
.matrix_key_map = mainstone_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(mainstone_matrix_keys),
.matrix_keymap_data = &mainstone_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,

View file

@ -222,7 +222,7 @@ static struct pxafb_mach_info mioa701_pxafb_info = {
/*
* Keyboard configuration
*/
static unsigned int mioa701_matrix_keys[] = {
static const unsigned int mioa701_matrix_keys[] = {
KEY(0, 0, KEY_UP),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_MEDIA),
@ -233,11 +233,16 @@ static unsigned int mioa701_matrix_keys[] = {
KEY(2, 1, KEY_PHONE), /* Phone Green key */
KEY(2, 2, KEY_CAMERA) /* Camera key */
};
static struct matrix_keymap_data mioa701_matrix_keymap_data = {
.keymap = mioa701_matrix_keys,
.keymap_size = ARRAY_SIZE(mioa701_matrix_keys),
};
static struct pxa27x_keypad_platform_data mioa701_keypad_info = {
.matrix_key_rows = 3,
.matrix_key_cols = 3,
.matrix_key_map = mioa701_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(mioa701_matrix_keys),
.matrix_keymap_data = &mioa701_matrix_keymap_data,
};
/*

View file

@ -173,7 +173,7 @@ static inline void palmld_nor_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int palmld_matrix_keys[] = {
static const unsigned int palmld_matrix_keys[] = {
KEY(0, 1, KEY_F2),
KEY(0, 2, KEY_UP),
@ -190,11 +190,15 @@ static unsigned int palmld_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
static struct matrix_keymap_data palmld_matrix_keymap_data = {
.keymap = palmld_matrix_keys,
.keymap_size = ARRAY_SIZE(palmld_matrix_keys),
};
static struct pxa27x_keypad_platform_data palmld_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
.matrix_key_map = palmld_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(palmld_matrix_keys),
.matrix_keymap_data = &palmld_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -108,7 +108,7 @@ static unsigned long palmt5_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int palmt5_matrix_keys[] = {
static const unsigned int palmt5_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@ -124,11 +124,15 @@ static unsigned int palmt5_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
static struct matrix_keymap_data palmt5_matrix_keymap_data = {
.keymap = palmt5_matrix_keys,
.keymap_size = ARRAY_SIZE(palmt5_matrix_keys),
};
static struct pxa27x_keypad_platform_data palmt5_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
.matrix_key_map = palmt5_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(palmt5_matrix_keys),
.matrix_keymap_data = &palmt5_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -168,7 +168,7 @@ static unsigned long centro685_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if IS_ENABLED(CONFIG_KEYBOARD_PXA27x)
static unsigned int treo680_matrix_keys[] = {
static const unsigned int treo680_matrix_keys[] = {
KEY(0, 0, KEY_F8), /* Red/Off/Power */
KEY(0, 1, KEY_LEFT),
KEY(0, 2, KEY_LEFTCTRL), /* Alternate */
@ -227,7 +227,7 @@ static unsigned int treo680_matrix_keys[] = {
KEY(7, 5, KEY_I),
};
static unsigned int centro_matrix_keys[] = {
static const unsigned int centro_matrix_keys[] = {
KEY(0, 0, KEY_F9), /* Home */
KEY(0, 1, KEY_LEFT),
KEY(0, 2, KEY_LEFTCTRL), /* Alternate */
@ -286,11 +286,20 @@ static unsigned int centro_matrix_keys[] = {
KEY(7, 5, KEY_I),
};
static struct matrix_keymap_data treo680_matrix_keymap_data = {
.keymap = treo680_matrix_keys,
.keymap_size = ARRAY_SIZE(treo680_matrix_keys),
};
static struct matrix_keymap_data centro_matrix_keymap_data = {
.keymap = centro_matrix_keys,
.keymap_size = ARRAY_SIZE(centro_matrix_keys),
};
static struct pxa27x_keypad_platform_data treo680_keypad_pdata = {
.matrix_key_rows = 8,
.matrix_key_cols = 7,
.matrix_key_map = treo680_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(treo680_matrix_keys),
.matrix_keymap_data = &treo680_matrix_keymap_data,
.direct_key_map = { KEY_CONNECT },
.direct_key_num = 1,
@ -301,10 +310,8 @@ static void __init palmtreo_kpc_init(void)
{
static struct pxa27x_keypad_platform_data *data = &treo680_keypad_pdata;
if (machine_is_centro()) {
data->matrix_key_map = centro_matrix_keys;
data->matrix_key_map_size = ARRAY_SIZE(centro_matrix_keys);
}
if (machine_is_centro())
data->matrix_keymap_data = &centro_matrix_keymap_data;
pxa_set_keypad_info(&treo680_keypad_pdata);
}

View file

@ -176,7 +176,7 @@ static inline void palmtx_nor_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int palmtx_matrix_keys[] = {
static const unsigned int palmtx_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@ -192,11 +192,15 @@ static unsigned int palmtx_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
static struct matrix_keymap_data palmtx_matrix_keymap_data = {
.keymap = palmtx_matrix_keys,
.keymap_size = ARRAY_SIZE(palmtx_matrix_keys),
};
static struct pxa27x_keypad_platform_data palmtx_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
.matrix_key_map = palmtx_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(palmtx_matrix_keys),
.matrix_keymap_data = &palmtx_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -140,7 +140,7 @@ static unsigned long palmz72_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int palmz72_matrix_keys[] = {
static const unsigned int palmz72_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@ -156,11 +156,15 @@ static unsigned int palmz72_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
static struct matrix_keymap_data almz72_matrix_keymap_data = {
.keymap = palmz72_matrix_keys,
.keymap_size = ARRAY_SIZE(palmz72_matrix_keys),
};
static struct pxa27x_keypad_platform_data palmz72_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
.matrix_key_map = palmz72_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(palmz72_matrix_keys),
.matrix_keymap_data = &almz72_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -106,7 +106,7 @@ static struct platform_device smc91x_device = {
};
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int tavorevb_matrix_key_map[] = {
static const unsigned int tavorevb_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(0, 4, KEY_A), KEY(0, 5, KEY_B), KEY(0, 6, KEY_C),
KEY(1, 4, KEY_E), KEY(1, 5, KEY_F), KEY(1, 6, KEY_G),
@ -147,11 +147,15 @@ static unsigned int tavorevb_matrix_key_map[] = {
KEY(3, 3, KEY_F23), /* soft2 */
};
static struct matrix_keymap_data tavorevb_matrix_keymap_data = {
.keymap = tavorevb_matrix_key_map,
.keymap_size = ARRAY_SIZE(tavorevb_matrix_key_map),
};
static struct pxa27x_keypad_platform_data tavorevb_keypad_info = {
.matrix_key_rows = 7,
.matrix_key_cols = 7,
.matrix_key_map = tavorevb_matrix_key_map,
.matrix_key_map_size = ARRAY_SIZE(tavorevb_matrix_key_map),
.matrix_keymap_data = &tavorevb_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -345,7 +345,7 @@ static inline void z2_leds_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int z2_matrix_keys[] = {
static const unsigned int z2_matrix_keys[] = {
KEY(0, 0, KEY_OPTION),
KEY(1, 0, KEY_UP),
KEY(2, 0, KEY_DOWN),
@ -405,11 +405,15 @@ static unsigned int z2_matrix_keys[] = {
KEY(5, 7, KEY_DOT),
};
static struct matrix_keymap_data z2_matrix_keymap_data = {
.keymap = z2_matrix_keys,
.keymap_size = ARRAY_SIZE(z2_matrix_keys),
};
static struct pxa27x_keypad_platform_data z2_keypad_platform_data = {
.matrix_key_rows = 7,
.matrix_key_cols = 8,
.matrix_key_map = z2_matrix_keys,
.matrix_key_map_size = ARRAY_SIZE(z2_matrix_keys),
.matrix_keymap_data = &z2_matrix_keymap_data,
.debounce_interval = 30,
};

View file

@ -263,7 +263,7 @@ static inline void zylonite_init_mmc(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
static unsigned int zylonite_matrix_key_map[] = {
static const unsigned int zylonite_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_C), KEY(0, 5, KEY_D),
KEY(1, 0, KEY_E), KEY(1, 1, KEY_F), KEY(1, 2, KEY_G), KEY(1, 5, KEY_H),
@ -306,11 +306,15 @@ static unsigned int zylonite_matrix_key_map[] = {
KEY(0, 3, KEY_AUX), /* contact */
};
static struct matrix_keymap_data zylonite_matrix_keymap_data = {
.keymap = zylonite_matrix_key_map,
.keymap_size = ARRAY_SIZE(zylonite_matrix_key_map),
};
static struct pxa27x_keypad_platform_data zylonite_keypad_info = {
.matrix_key_rows = 8,
.matrix_key_cols = 8,
.matrix_key_map = zylonite_matrix_key_map,
.matrix_key_map_size = ARRAY_SIZE(zylonite_matrix_key_map),
.matrix_keymap_data = &zylonite_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,

View file

@ -524,6 +524,12 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),

View file

@ -1547,6 +1547,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@ -2189,6 +2192,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }

View file

@ -135,6 +135,9 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240

View file

@ -52,6 +52,82 @@ struct evdev_client {
struct input_event buffer[];
};
/* flush queued events of type @type, caller must hold client->buffer_lock */
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
{
unsigned int i, head, num;
unsigned int mask = client->bufsize - 1;
bool is_report;
struct input_event *ev;
BUG_ON(type == EV_SYN);
head = client->tail;
client->packet_head = client->tail;
/* init to 1 so a leading SYN_REPORT will not be dropped */
num = 1;
for (i = client->tail; i != client->head; i = (i + 1) & mask) {
ev = &client->buffer[i];
is_report = ev->type == EV_SYN && ev->code == SYN_REPORT;
if (ev->type == type) {
/* drop matched entry */
continue;
} else if (is_report && !num) {
/* drop empty SYN_REPORT groups */
continue;
} else if (head != i) {
/* move entry to fill the gap */
client->buffer[head].time = ev->time;
client->buffer[head].type = ev->type;
client->buffer[head].code = ev->code;
client->buffer[head].value = ev->value;
}
num++;
head = (head + 1) & mask;
if (is_report) {
num = 0;
client->packet_head = head;
}
}
client->head = head;
}
/* queue SYN_DROPPED event */
static void evdev_queue_syn_dropped(struct evdev_client *client)
{
unsigned long flags;
struct input_event ev;
ktime_t time;
time = ktime_get();
if (client->clkid != CLOCK_MONOTONIC)
time = ktime_sub(time, ktime_get_monotonic_offset());
ev.time = ktime_to_timeval(time);
ev.type = EV_SYN;
ev.code = SYN_DROPPED;
ev.value = 0;
spin_lock_irqsave(&client->buffer_lock, flags);
client->buffer[client->head++] = ev;
client->head &= client->bufsize - 1;
if (unlikely(client->head == client->tail)) {
/* drop queue but keep our SYN_DROPPED event */
client->tail = (client->head - 1) & (client->bufsize - 1);
client->packet_head = client->tail;
}
spin_unlock_irqrestore(&client->buffer_lock, flags);
}
static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
@ -650,6 +726,51 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
return input_set_keycode(dev, &ke);
}
/*
* If we transfer state to the user, we should flush all pending events
* of the same type from the client's queue. Otherwise, they might end up
* with duplicate events, which can screw up client's state tracking.
* If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED
* event so user-space will notice missing events.
*
* LOCKING:
* We need to take event_lock before buffer_lock to avoid dead-locks. But we
* need the even_lock only to guarantee consistent state. We can safely release
* it while flushing the queue. This allows input-core to handle filters while
* we flush the queue.
*/
static int evdev_handle_get_val(struct evdev_client *client,
struct input_dev *dev, unsigned int type,
unsigned long *bits, unsigned int max,
unsigned int size, void __user *p, int compat)
{
int ret;
unsigned long *mem;
mem = kmalloc(sizeof(unsigned long) * max, GFP_KERNEL);
if (!mem)
return -ENOMEM;
spin_lock_irq(&dev->event_lock);
spin_lock(&client->buffer_lock);
memcpy(mem, bits, sizeof(unsigned long) * max);
spin_unlock(&dev->event_lock);
__evdev_flush_queue(client, type);
spin_unlock_irq(&client->buffer_lock);
ret = bits_to_user(mem, max, size, p, compat);
if (ret < 0)
evdev_queue_syn_dropped(client);
kfree(mem);
return ret;
}
static int evdev_handle_mt_request(struct input_dev *dev,
unsigned int size,
int __user *ip)
@ -771,16 +892,20 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_handle_mt_request(dev, size, ip);
case EVIOCGKEY(0):
return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
return evdev_handle_get_val(client, dev, EV_KEY, dev->key,
KEY_MAX, size, p, compat_mode);
case EVIOCGLED(0):
return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
return evdev_handle_get_val(client, dev, EV_LED, dev->led,
LED_MAX, size, p, compat_mode);
case EVIOCGSND(0):
return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
return evdev_handle_get_val(client, dev, EV_SND, dev->snd,
SND_MAX, size, p, compat_mode);
case EVIOCGSW(0):
return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
return evdev_handle_get_val(client, dev, EV_SW, dev->sw,
SW_MAX, size, p, compat_mode);
case EVIOCGNAME(0):
return str_to_user(dev->name, size, p);

View file

@ -418,6 +418,16 @@ config KEYBOARD_NOMADIK
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
config KEYBOARD_NSPIRE
tristate "TI-NSPIRE built-in keyboard"
depends on ARCH_NSPIRE && OF
select INPUT_MATRIXKMAP
help
Say Y here if you want to use the built-in keypad on TI-NSPIRE.
To compile this driver as a module, choose M here: the
module will be called nspire-keypad.
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
depends on ARCH_TEGRA && OF
@ -442,6 +452,7 @@ config KEYBOARD_OPENCORES
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx || ARCH_MMP
select INPUT_MATRIXKMAP
help
Enable support for PXA27x/PXA3xx keypad controller.

View file

@ -36,6 +36,7 @@ obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o

View file

@ -246,7 +246,6 @@ static int __exit amikbd_remove(struct platform_device *pdev)
{
struct input_dev *dev = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
free_irq(IRQ_AMIGA_CIAA_SP, dev);
input_unregister_device(dev);
return 0;

View file

@ -326,7 +326,6 @@ out0:
kfree(bf54x_kpad->keycode);
out:
kfree(bf54x_kpad);
platform_set_drvdata(pdev, NULL);
return error;
}
@ -346,7 +345,6 @@ static int bfin_kpad_remove(struct platform_device *pdev)
kfree(bf54x_kpad->keycode);
kfree(bf54x_kpad);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -314,8 +314,6 @@ static int davinci_ks_remove(struct platform_device *pdev)
iounmap(davinci_ks->base);
release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
platform_set_drvdata(pdev, NULL);
kfree(davinci_ks);
return 0;

View file

@ -329,8 +329,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
free_irq(keypad->irq, pdev);
platform_set_drvdata(pdev, NULL);
free_irq(keypad->irq, keypad);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
@ -351,9 +350,7 @@ static int ep93xx_keypad_remove(struct platform_device *pdev)
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad->irq, pdev);
platform_set_drvdata(pdev, NULL);
free_irq(keypad->irq, keypad);
if (keypad->enabled)
clk_disable(keypad->clk);

View file

@ -767,7 +767,6 @@ static int gpio_keys_probe(struct platform_device *pdev)
while (--i >= 0)
gpio_remove_key(&ddata->data[i]);
platform_set_drvdata(pdev, NULL);
fail1:
input_free_device(input);
kfree(ddata);

View file

@ -324,7 +324,6 @@ err_free_gpio:
err_free_bdev:
kfree(bdev);
platform_set_drvdata(pdev, NULL);
err_free_pdata:
/* If we have no platform_data, we allocated pdata dynamically. */
@ -355,7 +354,6 @@ static int gpio_keys_polled_remove(struct platform_device *pdev)
kfree(pdata);
kfree(bdev);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -233,7 +233,6 @@ static int jornada680kbd_probe(struct platform_device *pdev)
failed:
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
error);
platform_set_drvdata(pdev, NULL);
input_free_polled_device(poll_dev);
kfree(jornadakbd);
return error;
@ -244,7 +243,6 @@ static int jornada680kbd_remove(struct platform_device *pdev)
{
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
input_unregister_polled_device(jornadakbd->poll_dev);
input_free_polled_device(jornadakbd->poll_dev);
kfree(jornadakbd);

View file

@ -146,7 +146,6 @@ static int jornada720_kbd_probe(struct platform_device *pdev)
fail2: /* IRQ, DEVICE, MEMORY */
free_irq(IRQ_GPIO0, pdev);
fail1: /* DEVICE, MEMORY */
platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(jornadakbd);
return err;
@ -157,7 +156,6 @@ static int jornada720_kbd_remove(struct platform_device *pdev)
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO0, pdev);
platform_set_drvdata(pdev, NULL);
input_unregister_device(jornadakbd->input);
kfree(jornadakbd);

View file

@ -549,8 +549,6 @@ static int matrix_keypad_remove(struct platform_device *pdev)
input_unregister_device(keypad->input_dev);
kfree(keypad);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -0,0 +1,283 @@
/*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*/
#include <linux/input/matrix_keypad.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of.h>
#define KEYPAD_SCAN_MODE 0x00
#define KEYPAD_CNTL 0x04
#define KEYPAD_INT 0x08
#define KEYPAD_INTMSK 0x0C
#define KEYPAD_DATA 0x10
#define KEYPAD_GPIO 0x30
#define KEYPAD_UNKNOWN_INT 0x40
#define KEYPAD_UNKNOWN_INT_STS 0x44
#define KEYPAD_BITMASK_COLS 11
#define KEYPAD_BITMASK_ROWS 8
struct nspire_keypad {
void __iomem *reg_base;
u32 int_mask;
struct input_dev *input;
struct clk *clk;
struct matrix_keymap_data *keymap;
int row_shift;
/* Maximum delay estimated assuming 33MHz APB */
u32 scan_interval; /* In microseconds (~2000us max) */
u32 row_delay; /* In microseconds (~500us max) */
u16 state[KEYPAD_BITMASK_ROWS];
bool active_low;
};
static irqreturn_t nspire_keypad_irq(int irq, void *dev_id)
{
struct nspire_keypad *keypad = dev_id;
struct input_dev *input = keypad->input;
unsigned short *keymap = input->keycode;
unsigned int code;
int row, col;
u32 int_sts;
u16 state[8];
u16 bits, changed;
int_sts = readl(keypad->reg_base + KEYPAD_INT) & keypad->int_mask;
if (!int_sts)
return IRQ_NONE;
memcpy_fromio(state, keypad->reg_base + KEYPAD_DATA, sizeof(state));
for (row = 0; row < KEYPAD_BITMASK_ROWS; row++) {
bits = state[row];
if (keypad->active_low)
bits = ~bits;
changed = bits ^ keypad->state[row];
if (!changed)
continue;
keypad->state[row] = bits;
for (col = 0; col < KEYPAD_BITMASK_COLS; col++) {
if (!(changed & (1U << col)))
continue;
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
input_event(input, EV_MSC, MSC_SCAN, code);
input_report_key(input, keymap[code],
bits & (1U << col));
}
}
input_sync(input);
writel(0x3, keypad->reg_base + KEYPAD_INT);
return IRQ_HANDLED;
}
static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
{
unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
if (cycles_per_us == 0)
cycles_per_us = 1;
delay_cycles = cycles_per_us * keypad->scan_interval;
WARN_ON(delay_cycles >= (1 << 16)); /* Overflow */
delay_cycles &= 0xffff;
row_delay_cycles = cycles_per_us * keypad->row_delay;
WARN_ON(row_delay_cycles >= (1 << 14)); /* Overflow */
row_delay_cycles &= 0x3fff;
val |= 3 << 0; /* Set scan mode to 3 (continuous scan) */
val |= row_delay_cycles << 2; /* Delay between scanning each row */
val |= delay_cycles << 16; /* Delay between scans */
writel(val, keypad->reg_base + KEYPAD_SCAN_MODE);
val = (KEYPAD_BITMASK_ROWS & 0xff) | (KEYPAD_BITMASK_COLS & 0xff)<<8;
writel(val, keypad->reg_base + KEYPAD_CNTL);
/* Enable interrupts */
keypad->int_mask = 1 << 1;
writel(keypad->int_mask, keypad->reg_base + 0xc);
/* Disable GPIO interrupts to prevent hanging on touchpad */
/* Possibly used to detect touchpad events */
writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
/* Acknowledge existing interrupts */
writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
return 0;
}
static int nspire_keypad_open(struct input_dev *input)
{
struct nspire_keypad *keypad = input_get_drvdata(input);
int error;
error = clk_prepare_enable(keypad->clk);
if (error)
return error;
error = nspire_keypad_chip_init(keypad);
if (error)
return error;
return 0;
}
static void nspire_keypad_close(struct input_dev *input)
{
struct nspire_keypad *keypad = input_get_drvdata(input);
clk_disable_unprepare(keypad->clk);
}
static int nspire_keypad_probe(struct platform_device *pdev)
{
const struct device_node *of_node = pdev->dev.of_node;
struct nspire_keypad *keypad;
struct input_dev *input;
struct resource *res;
int irq;
int error;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get keypad irq\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing platform resources\n");
return -EINVAL;
}
keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad),
GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "failed to allocate keypad memory\n");
return -ENOMEM;
}
keypad->row_shift = get_count_order(KEYPAD_BITMASK_COLS);
error = of_property_read_u32(of_node, "scan-interval",
&keypad->scan_interval);
if (error) {
dev_err(&pdev->dev, "failed to get scan-interval\n");
return error;
}
error = of_property_read_u32(of_node, "row-delay",
&keypad->row_delay);
if (error) {
dev_err(&pdev->dev, "failed to get row-delay\n");
return error;
}
keypad->active_low = of_property_read_bool(of_node, "active-low");
keypad->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk)) {
dev_err(&pdev->dev, "unable to get clock\n");
return PTR_ERR(keypad->clk);
}
keypad->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(keypad->reg_base))
return PTR_ERR(keypad->reg_base);
keypad->input = input = devm_input_allocate_device(&pdev->dev);
if (!input) {
dev_err(&pdev->dev, "failed to allocate input device\n");
return -ENOMEM;
}
input_set_drvdata(input, keypad);
input->id.bustype = BUS_HOST;
input->name = "nspire-keypad";
input->open = nspire_keypad_open;
input->close = nspire_keypad_close;
__set_bit(EV_KEY, input->evbit);
__set_bit(EV_REP, input->evbit);
input_set_capability(input, EV_MSC, MSC_SCAN);
error = matrix_keypad_build_keymap(NULL, NULL,
KEYPAD_BITMASK_ROWS,
KEYPAD_BITMASK_COLS,
NULL, input);
if (error) {
dev_err(&pdev->dev, "building keymap failed\n");
return error;
}
error = devm_request_irq(&pdev->dev, irq, nspire_keypad_irq, 0,
"nspire_keypad", keypad);
if (error) {
dev_err(&pdev->dev, "allocate irq %d failed\n", irq);
return error;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev,
"unable to register input device: %d\n", error);
return error;
}
platform_set_drvdata(pdev, keypad);
dev_dbg(&pdev->dev,
"TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
res, keypad->row_delay, keypad->scan_interval,
keypad->active_low ? ", active_low" : "");
return 0;
}
static const struct of_device_id nspire_keypad_dt_match[] = {
{ .compatible = "ti,nspire-keypad" },
{ },
};
MODULE_DEVICE_TABLE(of, nspire_keypad_dt_match);
static struct platform_driver nspire_keypad_driver = {
.driver = {
.name = "nspire-keypad",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(nspire_keypad_dt_match),
},
.probe = nspire_keypad_probe,
};
module_platform_driver(nspire_keypad_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");

View file

@ -419,8 +419,6 @@ static int omap4_keypad_remove(struct platform_device *pdev)
kfree(keypad_data->keymap);
kfree(keypad_data);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -151,8 +151,6 @@ static int opencores_kbd_remove(struct platform_device *pdev)
input_unregister_device(opencores_kbd->input);
kfree(opencores_kbd);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -707,7 +707,6 @@ err_gpio_config:
err_get_irq:
input_free_device(kp->input);
err_alloc_device:
platform_set_drvdata(pdev, NULL);
kfree(kp);
return rc;
}
@ -722,7 +721,6 @@ static int pmic8xxx_kp_remove(struct platform_device *pdev)
input_unregister_device(kp->input);
kfree(kp);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -100,7 +100,7 @@
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
struct pxa27x_keypad {
struct pxa27x_keypad_platform_data *pdata;
const struct pxa27x_keypad_platform_data *pdata;
struct clk *clk;
struct input_dev *input_dev;
@ -118,25 +118,254 @@ struct pxa27x_keypad {
unsigned int direct_key_mask;
};
static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
#ifdef CONFIG_OF
static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
struct pxa27x_keypad_platform_data *pdata)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned short keycode;
int i;
struct device *dev = input_dev->dev.parent;
u32 rows, cols;
int error;
for (i = 0; i < pdata->matrix_key_map_size; i++) {
unsigned int key = pdata->matrix_key_map[i];
unsigned int row = KEY_ROW(key);
unsigned int col = KEY_COL(key);
unsigned int scancode = MATRIX_SCAN_CODE(row, col,
MATRIX_ROW_SHIFT);
error = matrix_keypad_parse_of_params(dev, &rows, &cols);
if (error)
return error;
keycode = KEY_VAL(key);
keypad->keycodes[scancode] = keycode;
__set_bit(keycode, input_dev->keybit);
if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
dev_err(dev, "rows or cols exceeds maximum value\n");
return -EINVAL;
}
pdata->matrix_key_rows = rows;
pdata->matrix_key_cols = cols;
error = matrix_keypad_build_keymap(NULL, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
if (error)
return error;
return 0;
}
static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
struct pxa27x_keypad_platform_data *pdata)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
const __be16 *prop;
unsigned short code;
unsigned int proplen, size;
int i;
int error;
error = of_property_read_u32(np, "marvell,direct-key-count",
&pdata->direct_key_num);
if (error) {
/*
* If do not have marvel,direct-key-count defined,
* it means direct key is not supported.
*/
return error == -EINVAL ? 0 : error;
}
error = of_property_read_u32(np, "marvell,direct-key-mask",
&pdata->direct_key_mask);
if (error) {
if (error != -EINVAL)
return error;
/*
* If marvell,direct-key-mask is not defined, driver will use
* default value. Default value is set when configure the keypad.
*/
pdata->direct_key_mask = 0;
}
pdata->direct_key_low_active = of_property_read_bool(np,
"marvell,direct-key-low-active");
prop = of_get_property(np, "marvell,direct-key-map", &proplen);
if (!prop)
return -EINVAL;
if (proplen % sizeof(u16))
return -EINVAL;
size = proplen / sizeof(u16);
/* Only MAX_DIRECT_KEY_NUM is accepted.*/
if (size > MAX_DIRECT_KEY_NUM)
return -EINVAL;
for (i = 0; i < size; i++) {
code = be16_to_cpup(prop + i);
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
__set_bit(code, input_dev->keybit);
}
return 0;
}
static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad,
struct pxa27x_keypad_platform_data *pdata)
{
const __be32 *prop;
int i, relkey_ret;
unsigned int code, proplen;
const char *rotaryname[2] = {
"marvell,rotary0", "marvell,rotary1"};
const char relkeyname[] = {"marvell,rotary-rel-key"};
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
relkey_ret = of_property_read_u32(np, relkeyname, &code);
/* if can read correct rotary key-code, we do not need this. */
if (relkey_ret == 0) {
unsigned short relcode;
/* rotary0 taks lower half, rotary1 taks upper half. */
relcode = code & 0xffff;
pdata->rotary0_rel_code = (code & 0xffff);
__set_bit(relcode, input_dev->relbit);
relcode = code >> 16;
pdata->rotary1_rel_code = relcode;
__set_bit(relcode, input_dev->relbit);
}
for (i = 0; i < 2; i++) {
prop = of_get_property(np, rotaryname[i], &proplen);
/*
* If the prop is not set, it means keypad does not need
* initialize the rotaryX.
*/
if (!prop)
continue;
code = be32_to_cpup(prop);
/*
* Not all up/down key code are valid.
* Now we depends on direct-rel-code.
*/
if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
return relkey_ret;
} else {
unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
unsigned short keycode;
keycode = code & 0xffff;
keypad->keycodes[n] = keycode;
__set_bit(keycode, input_dev->keybit);
keycode = code >> 16;
keypad->keycodes[n + 1] = keycode;
__set_bit(keycode, input_dev->keybit);
if (i == 0)
pdata->rotary0_rel_code = -1;
else
pdata->rotary1_rel_code = -1;
}
if (i == 0)
pdata->enable_rotary0 = 1;
else
pdata->enable_rotary1 = 1;
}
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
return 0;
}
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
struct device_node *np = dev->of_node;
struct pxa27x_keypad_platform_data *pdata;
int error;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "failed to allocate memory for pdata\n");
return -ENOMEM;
}
error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata);
if (error) {
dev_err(dev, "failed to parse matrix key\n");
return error;
}
error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata);
if (error) {
dev_err(dev, "failed to parse direct key\n");
return error;
}
error = pxa27x_keypad_rotary_parse_dt(keypad, pdata);
if (error) {
dev_err(dev, "failed to parse rotary key\n");
return error;
}
error = of_property_read_u32(np, "marvell,debounce-interval",
&pdata->debounce_interval);
if (error) {
dev_err(dev, "failed to parse debpunce-interval\n");
return error;
}
/*
* The keycodes may not only includes matrix key but also the direct
* key or rotary key.
*/
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
keypad->pdata = pdata;
return 0;
}
#else
static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
{
dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
return -EINVAL;
}
#endif
static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
{
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
const struct matrix_keymap_data *keymap_data =
pdata ? pdata->matrix_keymap_data : NULL;
unsigned short keycode;
int i;
int error;
error = matrix_keypad_build_keymap(keymap_data, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
if (error)
return error;
/*
* The keycodes may not only include matrix keys but also the direct
* or rotary keys.
*/
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
/* For direct keys. */
for (i = 0; i < pdata->direct_key_num; i++) {
keycode = pdata->direct_key_map[i];
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
@ -178,11 +407,13 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
return 0;
}
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
int row, col, num_keys_pressed = 0;
uint32_t new_state[MAX_MATRIX_KEY_COLS];
@ -284,7 +515,7 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
uint32_t kprec;
/* read and reset to default count value */
@ -300,7 +531,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned int new_state;
uint32_t kpdk, bits_changed;
@ -340,7 +571,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
static void clear_wakeup_event(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
if (pdata->clear_wakeup_event)
(pdata->clear_wakeup_event)();
@ -364,7 +595,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int mask = 0, direct_key_num = 0;
unsigned long kpc = 0;
@ -431,7 +662,7 @@ static void pxa27x_keypad_close(struct input_dev *dev)
clk_disable_unprepare(keypad->clk);
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int pxa27x_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@ -475,25 +706,25 @@ static int pxa27x_keypad_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
.suspend = pxa27x_keypad_suspend,
.resume = pxa27x_keypad_resume,
};
#endif
static SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops,
pxa27x_keypad_suspend, pxa27x_keypad_resume);
static int pxa27x_keypad_probe(struct platform_device *pdev)
{
struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
const struct pxa27x_keypad_platform_data *pdata =
dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
int irq, error;
if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
/* Driver need build keycode from device tree or pdata */
if (!np && !pdata)
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@ -555,7 +786,14 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
pxa27x_keypad_build_keycode(keypad);
if (pdata)
error = pxa27x_keypad_build_keycode(keypad);
else
error = pxa27x_keypad_build_keycode_from_dt(keypad);
if (error) {
dev_err(&pdev->dev, "failed to build keycode\n");
goto failed_put_clk;
}
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
@ -582,7 +820,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
free_irq(irq, pdev);
free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@ -600,7 +838,7 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad->irq, pdev);
free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
@ -609,7 +847,6 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
@ -618,15 +855,22 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:pxa27x-keypad");
#ifdef CONFIG_OF
static const struct of_device_id pxa27x_keypad_dt_match[] = {
{ .compatible = "marvell,pxa27x-keypad" },
{},
};
MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match);
#endif
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = pxa27x_keypad_remove,
.driver = {
.name = "pxa27x-keypad",
.of_match_table = of_match_ptr(pxa27x_keypad_dt_match),
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &pxa27x_keypad_pm_ops,
#endif
},
};
module_platform_driver(pxa27x_keypad_driver);

View file

@ -181,7 +181,6 @@ static int pxa930_rotary_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), r);
input_unregister_device(r->input_dev);
iounmap(r->mmio_base);
platform_set_drvdata(pdev, NULL);
kfree(r);
return 0;

View file

@ -24,7 +24,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/sched.h>
#include <linux/input/samsung-keypad.h>
@ -79,10 +78,6 @@ struct samsung_keypad {
unsigned int rows;
unsigned int cols;
unsigned int row_state[SAMSUNG_MAX_COLS];
#ifdef CONFIG_OF
int row_gpios[SAMSUNG_MAX_ROWS];
int col_gpios[SAMSUNG_MAX_COLS];
#endif
unsigned short keycodes[];
};
@ -304,45 +299,6 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
return pdata;
}
static void samsung_keypad_parse_dt_gpio(struct device *dev,
struct samsung_keypad *keypad)
{
struct device_node *np = dev->of_node;
int gpio, error, row, col;
for (row = 0; row < keypad->rows; row++) {
gpio = of_get_named_gpio(np, "row-gpios", row);
keypad->row_gpios[row] = gpio;
if (!gpio_is_valid(gpio)) {
dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
row, gpio);
continue;
}
error = devm_gpio_request(dev, gpio, "keypad-row");
if (error)
dev_err(dev,
"keypad row[%d] gpio request failed: %d\n",
row, error);
}
for (col = 0; col < keypad->cols; col++) {
gpio = of_get_named_gpio(np, "col-gpios", col);
keypad->col_gpios[col] = gpio;
if (!gpio_is_valid(gpio)) {
dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
col, gpio);
continue;
}
error = devm_gpio_request(dev, gpio, "keypad-col");
if (error)
dev_err(dev,
"keypad column[%d] gpio request failed: %d\n",
col, error);
}
}
#else
static
struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
@ -424,15 +380,11 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->stopped = true;
init_waitqueue_head(&keypad->wait);
if (pdev->dev.of_node) {
#ifdef CONFIG_OF
samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
if (pdev->dev.of_node)
keypad->type = of_device_is_compatible(pdev->dev.of_node,
"samsung,s5pv210-keypad");
#endif
} else {
else
keypad->type = platform_get_device_id(pdev)->driver_data;
}
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
@ -487,7 +439,6 @@ static int samsung_keypad_probe(struct platform_device *pdev)
err_disable_runtime_pm:
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
err_unprepare_clk:
clk_unprepare(keypad->clk);
return error;
@ -499,7 +450,6 @@ static int samsung_keypad_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
input_unregister_device(keypad->input_dev);

View file

@ -266,7 +266,6 @@ static int sh_keysc_probe(struct platform_device *pdev)
err2:
iounmap(priv->iomem_base);
err1:
platform_set_drvdata(pdev, NULL);
kfree(priv);
err0:
return error;
@ -285,7 +284,6 @@ static int sh_keysc_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;

View file

@ -290,7 +290,6 @@ static int spear_kbd_remove(struct platform_device *pdev)
clk_unprepare(kbd->clk);
device_init_wakeup(&pdev->dev, 0);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -296,7 +296,6 @@ error_clk:
error_map:
release_mem_region(kp->res->start, resource_size(kp->res));
error_res:
platform_set_drvdata(pdev, NULL);
kfree(kp);
return error;
}
@ -311,7 +310,6 @@ static int keypad_remove(struct platform_device *pdev)
clk_put(kp->clk);
iounmap(kp->regs);
release_mem_region(kp->res->start, resource_size(kp->res));
platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;

View file

@ -422,7 +422,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
err3:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
free_irq(kp->irq, NULL);
free_irq(kp->irq, kp);
err2:
input_unregister_device(input);
input = NULL;
@ -438,7 +438,6 @@ static int twl4030_kp_remove(struct platform_device *pdev)
free_irq(kp->irq, kp);
input_unregister_device(kp->input);
platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;

View file

@ -221,7 +221,7 @@ static int w90p910_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
free_irq(irq, pdev);
free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@ -239,7 +239,7 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(keypad->irq, pdev);
free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
@ -249,7 +249,6 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;

View file

@ -637,4 +637,14 @@ config INPUT_XEN_KBDDEV_FRONTEND
To compile this driver as a module, choose M here: the
module will be called xen-kbdfront.
config INPUT_SIRFSOC_ONKEY
bool "CSR SiRFSoC power on/off/suspend key support"
depends on ARCH_SIRF && OF
default y
help
Say Y here if you want to support for the SiRFSoC power on/off/suspend key
in Linux, after you press the onkey, system will suspend.
If unsure, say N.
endif

View file

@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o

View file

@ -127,8 +127,6 @@ static int ab8500_ponkey_remove(struct platform_device *pdev)
input_unregister_device(ponkey->idev);
kfree(ponkey);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -208,7 +208,6 @@ static int bfin_rotary_remove(struct platform_device *pdev)
peripheral_free_list(per_cnt);
kfree(rotary);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -184,8 +184,6 @@ static int gpio_tilt_polled_remove(struct platform_device *pdev)
struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
platform_set_drvdata(pdev, NULL);
input_unregister_polled_device(tdev->poll_dev);
input_free_polled_device(tdev->poll_dev);

View file

@ -125,7 +125,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
return 0;
err_free_irq:
free_irq(IRQ_IXP4XX_TIMER2, dev);
free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
err_free_device:
input_free_device(input_dev);
@ -138,13 +138,12 @@ static int ixp4xx_spkr_remove(struct platform_device *dev)
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
input_unregister_device(input_dev);
platform_set_drvdata(dev, NULL);
/* turn the speaker off */
disable_irq(IRQ_IXP4XX_TIMER2);
ixp4xx_spkr_control(pin, 0);
free_irq(IRQ_IXP4XX_TIMER2, dev);
free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
return 0;
}

View file

@ -85,7 +85,6 @@ static int m68kspkr_remove(struct platform_device *dev)
struct input_dev *input_dev = platform_get_drvdata(dev);
input_unregister_device(input_dev);
platform_set_drvdata(dev, NULL);
/* turn off the speaker */
m68kspkr_event(NULL, EV_SND, SND_BELL, 0);

View file

@ -148,8 +148,6 @@ static int max8925_onkey_remove(struct platform_device *pdev)
input_unregister_device(info->idev);
kfree(info);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -250,7 +250,6 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev)
input_unregister_device(priv->pwr);
kfree(priv);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -100,7 +100,6 @@ static int pcspkr_remove(struct platform_device *dev)
struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
input_unregister_device(pcspkr_dev);
platform_set_drvdata(dev, NULL);
/* turn off the speaker */
pcspkr_event(NULL, EV_SND, SND_BELL, 0);

View file

@ -249,8 +249,6 @@ static int pm8xxx_vib_remove(struct platform_device *pdev)
input_unregister_device(vib->vib_input_dev);
kfree(vib);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -175,9 +175,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
return 0;
free_press_irq:
free_irq(key_press_irq, NULL);
free_irq(key_press_irq, pwrkey);
unreg_input_dev:
platform_set_drvdata(pdev, NULL);
input_unregister_device(pwr);
pwr = NULL;
free_input_dev:
@ -198,7 +197,6 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
free_irq(key_press_irq, pwrkey);
free_irq(key_release_irq, pwrkey);
input_unregister_device(pwrkey->pwr);
platform_set_drvdata(pdev, NULL);
kfree(pwrkey);
return 0;

View file

@ -133,7 +133,6 @@ static int pwm_beeper_remove(struct platform_device *pdev)
{
struct pwm_beeper *beeper = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
input_unregister_device(beeper->input);
pwm_disable(beeper->pwm);

View file

@ -317,8 +317,6 @@ static int rotary_encoder_remove(struct platform_device *pdev)
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -128,7 +128,7 @@ static int sgi_buttons_probe(struct platform_device *pdev)
__clear_bit(KEY_RESERVED, input->keybit);
bdev->poll_dev = poll_dev;
dev_set_drvdata(&pdev->dev, bdev);
platform_set_drvdata(pdev, bdev);
error = input_register_polled_device(poll_dev);
if (error)
@ -139,19 +139,16 @@ static int sgi_buttons_probe(struct platform_device *pdev)
err_free_mem:
input_free_polled_device(poll_dev);
kfree(bdev);
dev_set_drvdata(&pdev->dev, NULL);
return error;
}
static int sgi_buttons_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct buttons_dev *bdev = dev_get_drvdata(dev);
struct buttons_dev *bdev = platform_get_drvdata(pdev);
input_unregister_polled_device(bdev->poll_dev);
input_free_polled_device(bdev->poll_dev);
kfree(bdev);
dev_set_drvdata(dev, NULL);
return 0;
}

View file

@ -0,0 +1,165 @@
/*
* Power key driver for SiRF PrimaII
*
* Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/rtc/sirfsoc_rtciobrg.h>
#include <linux/of.h>
struct sirfsoc_pwrc_drvdata {
u32 pwrc_base;
struct input_dev *input;
};
#define PWRC_ON_KEY_BIT (1 << 0)
#define PWRC_INT_STATUS 0xc
#define PWRC_INT_MASK 0x10
static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
{
struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
u32 int_status;
int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
PWRC_INT_STATUS);
sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_STATUS);
/*
* For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
* to queue a SUSPEND APM event
*/
input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
input_sync(pwrcdrv->input);
/*
* Todo: report KEY_POWER event for Android platforms, Android PowerManager
* will handle the suspend and powerdown/hibernation
*/
return IRQ_HANDLED;
}
static const struct of_device_id sirfsoc_pwrc_of_match[] = {
{ .compatible = "sirf,prima2-pwrc" },
{},
}
MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
static int sirfsoc_pwrc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct sirfsoc_pwrc_drvdata *pwrcdrv;
int irq;
int error;
pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
GFP_KERNEL);
if (!pwrcdrv) {
dev_info(&pdev->dev, "Not enough memory for the device data\n");
return -ENOMEM;
}
/*
* we can't use of_iomap because pwrc is not mapped in memory,
* the so-called base address is only offset in rtciobrg
*/
error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
if (error) {
dev_err(&pdev->dev,
"unable to find base address of pwrc node in dtb\n");
return error;
}
pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
if (!pwrcdrv->input)
return -ENOMEM;
pwrcdrv->input->name = "sirfsoc pwrckey";
pwrcdrv->input->phys = "pwrc/input0";
pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
irq = platform_get_irq(pdev, 0);
error = devm_request_irq(&pdev->dev, irq,
sirfsoc_pwrc_isr, IRQF_SHARED,
"sirfsoc_pwrc_int", pwrcdrv);
if (error) {
dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
irq, error);
return error;
}
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
error = input_register_device(pwrcdrv->input);
if (error) {
dev_err(&pdev->dev,
"unable to register input device, error: %d\n",
error);
return error;
}
platform_set_drvdata(pdev, pwrcdrv);
device_init_wakeup(&pdev->dev, 1);
return 0;
}
static int sirfsoc_pwrc_remove(struct platform_device *pdev)
{
device_init_wakeup(&pdev->dev, 0);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int pwrc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
/*
* Do not mask pwrc interrupt as we want pwrc work as a wakeup source
* if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
*/
sirfsoc_rtc_iobrg_writel(
sirfsoc_rtc_iobrg_readl(
pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
pwrcdrv->pwrc_base + PWRC_INT_MASK);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
static struct platform_driver sirfsoc_pwrc_driver = {
.probe = sirfsoc_pwrc_probe,
.remove = sirfsoc_pwrc_remove,
.driver = {
.name = "sirfsoc-pwrc",
.owner = THIS_MODULE,
.pm = &sirfsoc_pwrc_pm_ops,
.of_match_table = of_match_ptr(sirfsoc_pwrc_of_match),
}
};
module_platform_driver(sirfsoc_pwrc_driver);
MODULE_LICENSE("GPLv2");
MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
MODULE_ALIAS("platform:sirfsoc-pwrc");

View file

@ -175,7 +175,7 @@ static int sparcspkr_probe(struct device *dev)
static void sparcspkr_shutdown(struct platform_device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct sparcspkr_state *state = platform_get_drvdata(dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
@ -211,7 +211,7 @@ static int bbc_beep_probe(struct platform_device *op)
if (!info->regs)
goto out_free;
dev_set_drvdata(&op->dev, state);
platform_set_drvdata(op, state);
err = sparcspkr_probe(&op->dev);
if (err)
@ -220,7 +220,6 @@ static int bbc_beep_probe(struct platform_device *op)
return 0;
out_clear_drvdata:
dev_set_drvdata(&op->dev, NULL);
of_iounmap(&op->resource[0], info->regs, 6);
out_free:
@ -231,7 +230,7 @@ out_err:
static int bbc_remove(struct platform_device *op)
{
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
struct sparcspkr_state *state = platform_get_drvdata(op);
struct input_dev *input_dev = state->input_dev;
struct bbc_beep_info *info = &state->u.bbc;
@ -242,7 +241,6 @@ static int bbc_remove(struct platform_device *op)
of_iounmap(&op->resource[0], info->regs, 6);
dev_set_drvdata(&op->dev, NULL);
kfree(state);
return 0;
@ -290,7 +288,7 @@ static int grover_beep_probe(struct platform_device *op)
if (!info->enable_reg)
goto out_unmap_freq_regs;
dev_set_drvdata(&op->dev, state);
platform_set_drvdata(op, state);
err = sparcspkr_probe(&op->dev);
if (err)
@ -299,7 +297,6 @@ static int grover_beep_probe(struct platform_device *op)
return 0;
out_clear_drvdata:
dev_set_drvdata(&op->dev, NULL);
of_iounmap(&op->resource[3], info->enable_reg, 1);
out_unmap_freq_regs:
@ -312,7 +309,7 @@ out_err:
static int grover_remove(struct platform_device *op)
{
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
struct sparcspkr_state *state = platform_get_drvdata(op);
struct grover_beep_info *info = &state->u.grover;
struct input_dev *input_dev = state->input_dev;
@ -324,7 +321,6 @@ static int grover_remove(struct platform_device *op)
of_iounmap(&op->resource[3], info->enable_reg, 1);
of_iounmap(&op->resource[2], info->freq_regs, 2);
dev_set_drvdata(&op->dev, NULL);
kfree(state);
return 0;

View file

@ -133,7 +133,6 @@ static int __exit amimouse_remove(struct platform_device *pdev)
{
struct input_dev *dev = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
input_unregister_device(dev);
return 0;
}

View file

@ -88,6 +88,10 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
/* MacbookAir6,2 (unibody, June 2013) */
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@ -145,6 +149,10 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
/* MacbookAir6,2 */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
/* Terminating entry */
{}
};
@ -172,15 +180,18 @@ struct bt_data {
/* trackpad header types */
enum tp_type {
TYPE1, /* plain trackpad */
TYPE2 /* button integrated in trackpad */
TYPE2, /* button integrated in trackpad */
TYPE3 /* additional header fields since June 2013 */
};
/* trackpad finger data offsets, le16-aligned */
#define FINGER_TYPE1 (13 * sizeof(__le16))
#define FINGER_TYPE2 (15 * sizeof(__le16))
#define FINGER_TYPE3 (19 * sizeof(__le16))
/* trackpad button data offsets */
#define BUTTON_TYPE2 15
#define BUTTON_TYPE3 23
/* list of device capability bits */
#define HAS_INTEGRATED_BUTTON 1
@ -400,6 +411,19 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ SN_COORD, -150, 6730 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
},
{
USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI,
USB_DEVICE_ID_APPLE_WELLSPRING8_ISO,
USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
HAS_INTEGRATED_BUTTON,
0, sizeof(struct bt_data),
0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
{ SN_PRESSURE, 0, 300 },
{ SN_WIDTH, 0, 2048 },
{ SN_COORD, -4620, 5140 },
{ SN_COORD, -150, 6600 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
},
{}
};
@ -557,6 +581,9 @@ static int report_tp_state(struct bcm5974 *dev, int size)
input_report_key(input, BTN_LEFT, ibt);
}
if (c->tp_type == TYPE3)
input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
input_sync(input);
return 0;
@ -572,9 +599,14 @@ static int report_tp_state(struct bcm5974 *dev, int size)
static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
{
char *data = kmalloc(8, GFP_KERNEL);
int retval = 0, size;
char *data;
/* Type 3 does not require a mode switch */
if (dev->cfg.tp_type == TYPE3)
return 0;
data = kmalloc(8, GFP_KERNEL);
if (!data) {
dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;

View file

@ -138,7 +138,6 @@ static int gpio_mouse_probe(struct platform_device *pdev)
out_free_polldev:
input_free_polled_device(input_poll);
platform_set_drvdata(pdev, NULL);
out_free_gpios:
while (--i >= 0) {
@ -165,8 +164,6 @@ static int gpio_mouse_remove(struct platform_device *pdev)
gpio_free(pin);
}
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -287,7 +287,7 @@ static int navpoint_probe(struct platform_device *pdev)
return 0;
err_free_irq:
free_irq(ssp->irq, &pdev->dev);
free_irq(ssp->irq, navpoint);
err_free_mem:
input_free_device(input);
kfree(navpoint);

View file

@ -256,4 +256,14 @@ config SERIO_APBPS2
To compile this driver as a module, choose M here: the module will
be called apbps2.
config SERIO_OLPC_APSP
tristate "OLPC AP-SP input support"
depends on OF
help
Say Y here if you want support for the keyboard and touchpad included
in the OLPC XO-1.75 and XO-4 laptops.
To compile this driver as a module, choose M here: the module will
be called olpc_apsp.
endif

View file

@ -27,3 +27,4 @@ obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o

View file

@ -163,7 +163,6 @@ static int altera_ps2_remove(struct platform_device *pdev)
{
struct ps2if *ps2if = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
serio_unregister_port(ps2if->io);
free_irq(ps2if->irq, ps2if);
iounmap(ps2if->base);

View file

@ -314,8 +314,6 @@ static int __exit psif_remove(struct platform_device *pdev)
clk_put(psif->pclk);
kfree(psif);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -0,0 +1,287 @@
/*
* OLPC serio driver for multiplexed input from Marvell MMP security processor
*
* Copyright (C) 2011-2013 One Laptop Per Child
*
* 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.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/delay.h>
/*
* The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller.
* Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an
* otherwise-unused slow processor which is included in the Marvell MMP2/MMP3
* SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module"
* (WTM). This firmware then reports its results via the WTM registers,
* which we read from the Application Processor (AP, i.e. main CPU) in this
* driver.
*
* On the hardware side we have a PS/2 mouse and an AT keyboard, the data
* is multiplexed through this system. We create a serio port for each one,
* and demultiplex the data accordingly.
*/
/* WTM register offsets */
#define SECURE_PROCESSOR_COMMAND 0x40
#define COMMAND_RETURN_STATUS 0x80
#define COMMAND_FIFO_STATUS 0xc4
#define PJ_RST_INTERRUPT 0xc8
#define PJ_INTERRUPT_MASK 0xcc
/*
* The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is
* used to identify which port (device) is being talked to. The lower byte
* is the data being sent/received.
*/
#define PORT_MASK 0xff00
#define DATA_MASK 0x00ff
#define PORT_SHIFT 8
#define KEYBOARD_PORT 0
#define TOUCHPAD_PORT 1
/* COMMAND_FIFO_STATUS */
#define CMD_CNTR_MASK 0x7 /* Number of pending/unprocessed commands */
#define MAX_PENDING_CMDS 4 /* from device specs */
/* PJ_RST_INTERRUPT */
#define SP_COMMAND_COMPLETE_RESET 0x1
/* PJ_INTERRUPT_MASK */
#define INT_0 (1 << 0)
/* COMMAND_FIFO_STATUS */
#define CMD_STS_MASK 0x100
struct olpc_apsp {
struct device *dev;
struct serio *kbio;
struct serio *padio;
void __iomem *base;
int open_count;
int irq;
};
static int olpc_apsp_write(struct serio *port, unsigned char val)
{
struct olpc_apsp *priv = port->port_data;
unsigned int i;
u32 which = 0;
if (port == priv->padio)
which = TOUCHPAD_PORT << PORT_SHIFT;
else
which = KEYBOARD_PORT << PORT_SHIFT;
dev_dbg(priv->dev, "olpc_apsp_write which=%x val=%x\n", which, val);
for (i = 0; i < 50; i++) {
u32 sts = readl(priv->base + COMMAND_FIFO_STATUS);
if ((sts & CMD_CNTR_MASK) < MAX_PENDING_CMDS) {
writel(which | val,
priv->base + SECURE_PROCESSOR_COMMAND);
return 0;
}
/* SP busy. This has not been seen in practice. */
mdelay(1);
}
dev_dbg(priv->dev, "olpc_apsp_write timeout, status=%x\n",
readl(priv->base + COMMAND_FIFO_STATUS));
return -ETIMEDOUT;
}
static irqreturn_t olpc_apsp_rx(int irq, void *dev_id)
{
struct olpc_apsp *priv = dev_id;
unsigned int w, tmp;
struct serio *serio;
/*
* Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt
* Write 0xff00 to SECURE_PROCESSOR_COMMAND.
*/
tmp = readl(priv->base + PJ_RST_INTERRUPT);
if (!(tmp & SP_COMMAND_COMPLETE_RESET)) {
dev_warn(priv->dev, "spurious interrupt?\n");
return IRQ_NONE;
}
w = readl(priv->base + COMMAND_RETURN_STATUS);
dev_dbg(priv->dev, "olpc_apsp_rx %x\n", w);
if (w >> PORT_SHIFT == KEYBOARD_PORT)
serio = priv->kbio;
else
serio = priv->padio;
serio_interrupt(serio, w & DATA_MASK, 0);
/* Ack and clear interrupt */
writel(tmp | SP_COMMAND_COMPLETE_RESET, priv->base + PJ_RST_INTERRUPT);
writel(PORT_MASK, priv->base + SECURE_PROCESSOR_COMMAND);
pm_wakeup_event(priv->dev, 1000);
return IRQ_HANDLED;
}
static int olpc_apsp_open(struct serio *port)
{
struct olpc_apsp *priv = port->port_data;
unsigned int tmp;
if (priv->open_count++ == 0) {
/* Enable interrupt 0 by clearing its bit */
tmp = readl(priv->base + PJ_INTERRUPT_MASK);
writel(tmp & ~INT_0, priv->base + PJ_INTERRUPT_MASK);
}
return 0;
}
static void olpc_apsp_close(struct serio *port)
{
struct olpc_apsp *priv = port->port_data;
unsigned int tmp;
if (--priv->open_count == 0) {
/* Disable interrupt 0 */
tmp = readl(priv->base + PJ_INTERRUPT_MASK);
writel(tmp | INT_0, priv->base + PJ_INTERRUPT_MASK);
}
}
static int olpc_apsp_probe(struct platform_device *pdev)
{
struct serio *kb_serio, *pad_serio;
struct olpc_apsp *priv;
struct resource *res;
struct device_node *np;
unsigned long l;
int error;
priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL);
if (!priv)
return -ENOMEM;
np = pdev->dev.of_node;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base)) {
dev_err(&pdev->dev, "Failed to map WTM registers\n");
return PTR_ERR(priv->base);
}
priv->irq = platform_get_irq(pdev, 0);
if (priv->irq < 0)
return priv->irq;
l = readl(priv->base + COMMAND_FIFO_STATUS);
if (!(l & CMD_STS_MASK)) {
dev_err(&pdev->dev, "SP cannot accept commands.\n");
return -EIO;
}
/* KEYBOARD */
kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!kb_serio)
return -ENOMEM;
kb_serio->id.type = SERIO_8042_XL;
kb_serio->write = olpc_apsp_write;
kb_serio->open = olpc_apsp_open;
kb_serio->close = olpc_apsp_close;
kb_serio->port_data = priv;
kb_serio->dev.parent = &pdev->dev;
strlcpy(kb_serio->name, "sp keyboard", sizeof(kb_serio->name));
strlcpy(kb_serio->phys, "sp/serio0", sizeof(kb_serio->phys));
priv->kbio = kb_serio;
serio_register_port(kb_serio);
/* TOUCHPAD */
pad_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!pad_serio) {
error = -ENOMEM;
goto err_pad;
}
pad_serio->id.type = SERIO_8042;
pad_serio->write = olpc_apsp_write;
pad_serio->open = olpc_apsp_open;
pad_serio->close = olpc_apsp_close;
pad_serio->port_data = priv;
pad_serio->dev.parent = &pdev->dev;
strlcpy(pad_serio->name, "sp touchpad", sizeof(pad_serio->name));
strlcpy(pad_serio->phys, "sp/serio1", sizeof(pad_serio->phys));
priv->padio = pad_serio;
serio_register_port(pad_serio);
error = request_irq(priv->irq, olpc_apsp_rx, 0, "olpc-apsp", priv);
if (error) {
dev_err(&pdev->dev, "Failed to request IRQ\n");
goto err_irq;
}
priv->dev = &pdev->dev;
device_init_wakeup(priv->dev, 1);
platform_set_drvdata(pdev, priv);
dev_dbg(&pdev->dev, "probed successfully.\n");
return 0;
err_irq:
serio_unregister_port(pad_serio);
err_pad:
serio_unregister_port(kb_serio);
return error;
}
static int olpc_apsp_remove(struct platform_device *pdev)
{
struct olpc_apsp *priv = platform_get_drvdata(pdev);
free_irq(priv->irq, priv);
serio_unregister_port(priv->kbio);
serio_unregister_port(priv->padio);
return 0;
}
static struct of_device_id olpc_apsp_dt_ids[] = {
{ .compatible = "olpc,ap-sp", },
{}
};
MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids);
static struct platform_driver olpc_apsp_driver = {
.probe = olpc_apsp_probe,
.remove = olpc_apsp_remove,
.driver = {
.name = "olpc-apsp",
.owner = THIS_MODULE,
.of_match_table = olpc_apsp_dt_ids,
},
};
MODULE_DESCRIPTION("OLPC AP-SP serio driver");
MODULE_LICENSE("GPL");
module_platform_driver(olpc_apsp_driver);

View file

@ -181,7 +181,6 @@ static int q40kbd_remove(struct platform_device *pdev)
free_irq(Q40_IRQ_KEYBOARD, q40kbd);
kfree(q40kbd);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -349,8 +349,6 @@ static int xps2_of_remove(struct platform_device *of_dev)
kfree(drvdata);
platform_set_drvdata(of_dev, NULL);
return 0;
}

View file

@ -237,7 +237,7 @@ static int pm860x_touch_probe(struct platform_device *pdev)
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
if (touch == NULL)
return -ENOMEM;
dev_set_drvdata(&pdev->dev, touch);
platform_set_drvdata(pdev, touch);
touch->idev = input_allocate_device();
if (touch->idev == NULL) {
@ -299,7 +299,6 @@ static int pm860x_touch_remove(struct platform_device *pdev)
input_unregister_device(touch->idev);
free_irq(touch->irq, touch);
platform_set_drvdata(pdev, NULL);
kfree(touch);
return 0;
}

View file

@ -167,6 +167,36 @@ config TOUCHSCREEN_CYTTSP_SPI
To compile this driver as a module, choose M here: the
module will be called cyttsp_spi.
config TOUCHSCREEN_CYTTSP4_CORE
tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
help
Core driver for Cypress TrueTouch(tm) Standard Product
Generation4 touchscreen controllers.
Say Y here if you have a Cypress Gen4 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here.
config TOUCHSCREEN_CYTTSP4_I2C
tristate "support I2C bus connection"
depends on TOUCHSCREEN_CYTTSP4_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 cyttsp4_i2c.
config TOUCHSCREEN_CYTTSP4_SPI
tristate "support SPI bus connection"
depends on TOUCHSCREEN_CYTTSP4_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 cyttsp4_spi.
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
@ -879,6 +909,7 @@ config TOUCHSCREEN_STMPE
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
select INPUT_POLLDEV
help
Say Y here if you have a TPS6507x based touchscreen
controller.

View file

@ -18,8 +18,11 @@ obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-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_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o

View file

@ -372,7 +372,6 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
err_irq:
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
err:
platform_set_drvdata(pdev, NULL);
kfree(atmel_wm97xx);
return ret;
}
@ -386,7 +385,6 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
del_timer_sync(&atmel_wm97xx->pen_timer);
wm97xx_unregister_mach_ops(wm);
platform_set_drvdata(pdev, NULL);
kfree(atmel_wm97xx);
return 0;

View file

@ -183,10 +183,13 @@ static int atmel_tsadcc_probe(struct platform_device *pdev)
struct input_dev *input_dev;
struct resource *res;
struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
int err = 0;
int err;
unsigned int prsc;
unsigned int reg;
if (!pdata)
return -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mmio resource defined.\n");
@ -265,9 +268,6 @@ static int atmel_tsadcc_probe(struct platform_device *pdev)
prsc = clk_get_rate(ts_dev->clk);
dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
if (!pdata)
goto err_fail;
if (!pdata->adc_clock)
pdata->adc_clock = ADC_DEFAULT_CLOCK;
@ -325,7 +325,7 @@ err_free_mem:
static int atmel_tsadcc_remove(struct platform_device *pdev)
{
struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev);
struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev);
struct resource *res;
free_irq(ts_dev->irq, ts_dev);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,472 @@
/*
* cyttsp4_core.h
* Cypress TrueTouch(TM) Standard Product V4 Core driver module.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2012 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#ifndef _LINUX_CYTTSP4_CORE_H
#define _LINUX_CYTTSP4_CORE_H
#include <linux/device.h>
#include <linux/err.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/module.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/platform_data/cyttsp4.h>
#define CY_REG_BASE 0x00
#define CY_POST_CODEL_WDG_RST 0x01
#define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02
#define CY_POST_CODEL_PANEL_TEST_FAIL 0x04
#define CY_NUM_BTN_PER_REG 4
/* touch record system information offset masks and shifts */
#define CY_BYTE_OFS_MASK 0x1F
#define CY_BOFS_MASK 0xE0
#define CY_BOFS_SHIFT 5
#define CY_TMA1036_TCH_REC_SIZE 6
#define CY_TMA4XX_TCH_REC_SIZE 9
#define CY_TMA1036_MAX_TCH 0x0E
#define CY_TMA4XX_MAX_TCH 0x1E
#define CY_NORMAL_ORIGIN 0 /* upper, left corner */
#define CY_INVERT_ORIGIN 1 /* lower, right corner */
/* helpers */
#define GET_NUM_TOUCHES(x) ((x) & 0x1F)
#define IS_LARGE_AREA(x) ((x) & 0x20)
#define IS_BAD_PKT(x) ((x) & 0x20)
#define IS_BOOTLOADER(hst_mode, reset_detect) \
((hst_mode) & 0x01 || (reset_detect) != 0)
#define IS_TMO(t) ((t) == 0)
enum cyttsp_cmd_bits {
CY_CMD_COMPLETE = (1 << 6),
};
/* Timeout in ms. */
#define CY_WATCHDOG_TIMEOUT 1000
#define CY_MAX_PRINT_SIZE 512
#ifdef VERBOSE_DEBUG
#define CY_MAX_PRBUF_SIZE PIPE_BUF
#define CY_PR_TRUNCATED " truncated..."
#endif
enum cyttsp4_ic_grpnum {
CY_IC_GRPNUM_RESERVED,
CY_IC_GRPNUM_CMD_REGS,
CY_IC_GRPNUM_TCH_REP,
CY_IC_GRPNUM_DATA_REC,
CY_IC_GRPNUM_TEST_REC,
CY_IC_GRPNUM_PCFG_REC,
CY_IC_GRPNUM_TCH_PARM_VAL,
CY_IC_GRPNUM_TCH_PARM_SIZE,
CY_IC_GRPNUM_RESERVED1,
CY_IC_GRPNUM_RESERVED2,
CY_IC_GRPNUM_OPCFG_REC,
CY_IC_GRPNUM_DDATA_REC,
CY_IC_GRPNUM_MDATA_REC,
CY_IC_GRPNUM_TEST_REGS,
CY_IC_GRPNUM_BTN_KEYS,
CY_IC_GRPNUM_TTHE_REGS,
CY_IC_GRPNUM_NUM
};
enum cyttsp4_int_state {
CY_INT_NONE,
CY_INT_IGNORE = (1 << 0),
CY_INT_MODE_CHANGE = (1 << 1),
CY_INT_EXEC_CMD = (1 << 2),
CY_INT_AWAKE = (1 << 3),
};
enum cyttsp4_mode {
CY_MODE_UNKNOWN,
CY_MODE_BOOTLOADER = (1 << 1),
CY_MODE_OPERATIONAL = (1 << 2),
CY_MODE_SYSINFO = (1 << 3),
CY_MODE_CAT = (1 << 4),
CY_MODE_STARTUP = (1 << 5),
CY_MODE_LOADER = (1 << 6),
CY_MODE_CHANGE_MODE = (1 << 7),
CY_MODE_CHANGED = (1 << 8),
CY_MODE_CMD_COMPLETE = (1 << 9),
};
enum cyttsp4_sleep_state {
SS_SLEEP_OFF,
SS_SLEEP_ON,
SS_SLEEPING,
SS_WAKING,
};
enum cyttsp4_startup_state {
STARTUP_NONE,
STARTUP_QUEUED,
STARTUP_RUNNING,
};
#define CY_NUM_REVCTRL 8
struct cyttsp4_cydata {
u8 ttpidh;
u8 ttpidl;
u8 fw_ver_major;
u8 fw_ver_minor;
u8 revctrl[CY_NUM_REVCTRL];
u8 blver_major;
u8 blver_minor;
u8 jtag_si_id3;
u8 jtag_si_id2;
u8 jtag_si_id1;
u8 jtag_si_id0;
u8 mfgid_sz;
u8 cyito_idh;
u8 cyito_idl;
u8 cyito_verh;
u8 cyito_verl;
u8 ttsp_ver_major;
u8 ttsp_ver_minor;
u8 device_info;
u8 mfg_id[];
} __packed;
struct cyttsp4_test {
u8 post_codeh;
u8 post_codel;
} __packed;
struct cyttsp4_pcfg {
u8 electrodes_x;
u8 electrodes_y;
u8 len_xh;
u8 len_xl;
u8 len_yh;
u8 len_yl;
u8 res_xh;
u8 res_xl;
u8 res_yh;
u8 res_yl;
u8 max_zh;
u8 max_zl;
u8 panel_info0;
} __packed;
struct cyttsp4_tch_rec_params {
u8 loc;
u8 size;
} __packed;
#define CY_NUM_TCH_FIELDS 7
#define CY_NUM_EXT_TCH_FIELDS 3
struct cyttsp4_opcfg {
u8 cmd_ofs;
u8 rep_ofs;
u8 rep_szh;
u8 rep_szl;
u8 num_btns;
u8 tt_stat_ofs;
u8 obj_cfg0;
u8 max_tchs;
u8 tch_rec_size;
struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS];
u8 btn_rec_size; /* btn record size (in bytes) */
u8 btn_diff_ofs; /* btn data loc, diff counts */
u8 btn_diff_size; /* btn size of diff counts (in bits) */
struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS];
} __packed;
struct cyttsp4_sysinfo_ptr {
struct cyttsp4_cydata *cydata;
struct cyttsp4_test *test;
struct cyttsp4_pcfg *pcfg;
struct cyttsp4_opcfg *opcfg;
struct cyttsp4_ddata *ddata;
struct cyttsp4_mdata *mdata;
} __packed;
struct cyttsp4_sysinfo_data {
u8 hst_mode;
u8 reserved;
u8 map_szh;
u8 map_szl;
u8 cydata_ofsh;
u8 cydata_ofsl;
u8 test_ofsh;
u8 test_ofsl;
u8 pcfg_ofsh;
u8 pcfg_ofsl;
u8 opcfg_ofsh;
u8 opcfg_ofsl;
u8 ddata_ofsh;
u8 ddata_ofsl;
u8 mdata_ofsh;
u8 mdata_ofsl;
} __packed;
enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
CY_TCH_X, /* X */
CY_TCH_Y, /* Y */
CY_TCH_P, /* P (Z) */
CY_TCH_T, /* TOUCH ID */
CY_TCH_E, /* EVENT ID */
CY_TCH_O, /* OBJECT ID */
CY_TCH_W, /* SIZE */
CY_TCH_MAJ, /* TOUCH_MAJOR */
CY_TCH_MIN, /* TOUCH_MINOR */
CY_TCH_OR, /* ORIENTATION */
CY_TCH_NUM_ABS
};
static const char * const cyttsp4_tch_abs_string[] = {
[CY_TCH_X] = "X",
[CY_TCH_Y] = "Y",
[CY_TCH_P] = "P",
[CY_TCH_T] = "T",
[CY_TCH_E] = "E",
[CY_TCH_O] = "O",
[CY_TCH_W] = "W",
[CY_TCH_MAJ] = "MAJ",
[CY_TCH_MIN] = "MIN",
[CY_TCH_OR] = "OR",
[CY_TCH_NUM_ABS] = "INVALID"
};
struct cyttsp4_touch {
int abs[CY_TCH_NUM_ABS];
};
struct cyttsp4_tch_abs_params {
size_t ofs; /* abs byte offset */
size_t size; /* size in bits */
size_t max; /* max value */
size_t bofs; /* bit offset */
};
struct cyttsp4_sysinfo_ofs {
size_t chip_type;
size_t cmd_ofs;
size_t rep_ofs;
size_t rep_sz;
size_t num_btns;
size_t num_btn_regs; /* ceil(num_btns/4) */
size_t tt_stat_ofs;
size_t tch_rec_size;
size_t obj_cfg0;
size_t max_tchs;
size_t mode_size;
size_t data_size;
size_t map_sz;
size_t max_x;
size_t x_origin; /* left or right corner */
size_t max_y;
size_t y_origin; /* upper or lower corner */
size_t max_p;
size_t cydata_ofs;
size_t test_ofs;
size_t pcfg_ofs;
size_t opcfg_ofs;
size_t ddata_ofs;
size_t mdata_ofs;
size_t cydata_size;
size_t test_size;
size_t pcfg_size;
size_t opcfg_size;
size_t ddata_size;
size_t mdata_size;
size_t btn_keys_size;
struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
size_t btn_rec_size; /* btn record size (in bytes) */
size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */
size_t btn_diff_size;/* btn size of diff counts (in bits) */
};
enum cyttsp4_btn_state {
CY_BTN_RELEASED,
CY_BTN_PRESSED,
CY_BTN_NUM_STATE
};
struct cyttsp4_btn {
bool enabled;
int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */
int key_code;
};
struct cyttsp4_sysinfo {
bool ready;
struct cyttsp4_sysinfo_data si_data;
struct cyttsp4_sysinfo_ptr si_ptrs;
struct cyttsp4_sysinfo_ofs si_ofs;
struct cyttsp4_btn *btn; /* button states */
u8 *btn_rec_data; /* button diff count data */
u8 *xy_mode; /* operational mode and status regs */
u8 *xy_data; /* operational touch regs */
};
struct cyttsp4_mt_data {
struct cyttsp4_mt_platform_data *pdata;
struct cyttsp4_sysinfo *si;
struct input_dev *input;
struct mutex report_lock;
bool is_suspended;
char phys[NAME_MAX];
int num_prv_tch;
};
struct cyttsp4 {
struct device *dev;
struct mutex system_lock;
struct mutex adap_lock;
enum cyttsp4_mode mode;
enum cyttsp4_sleep_state sleep_state;
enum cyttsp4_startup_state startup_state;
int int_status;
wait_queue_head_t wait_q;
int irq;
struct work_struct startup_work;
struct work_struct watchdog_work;
struct timer_list watchdog_timer;
struct cyttsp4_sysinfo sysinfo;
void *exclusive_dev;
int exclusive_waits;
atomic_t ignore_irq;
bool invalid_touch_app;
struct cyttsp4_mt_data md;
struct cyttsp4_platform_data *pdata;
struct cyttsp4_core_platform_data *cpdata;
const struct cyttsp4_bus_ops *bus_ops;
u8 *xfer_buf;
#ifdef VERBOSE_DEBUG
u8 pr_buf[CY_MAX_PRBUF_SIZE];
#endif
};
struct cyttsp4_bus_ops {
u16 bustype;
int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
const void *values);
int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
void *values);
};
enum cyttsp4_hst_mode_bits {
CY_HST_TOGGLE = (1 << 7),
CY_HST_MODE_CHANGE = (1 << 3),
CY_HST_MODE = (7 << 4),
CY_HST_OPERATE = (0 << 4),
CY_HST_SYSINFO = (1 << 4),
CY_HST_CAT = (2 << 4),
CY_HST_LOWPOW = (1 << 2),
CY_HST_SLEEP = (1 << 1),
CY_HST_RESET = (1 << 0),
};
/* abs settings */
#define CY_IGNORE_VALUE 0xFFFF
/* abs signal capabilities offsets in the frameworks array */
enum cyttsp4_sig_caps {
CY_SIGNAL_OST,
CY_MIN_OST,
CY_MAX_OST,
CY_FUZZ_OST,
CY_FLAT_OST,
CY_NUM_ABS_SET /* number of signal capability fields */
};
/* abs axis signal offsets in the framworks array */
enum cyttsp4_sig_ost {
CY_ABS_X_OST,
CY_ABS_Y_OST,
CY_ABS_P_OST,
CY_ABS_W_OST,
CY_ABS_ID_OST,
CY_ABS_MAJ_OST,
CY_ABS_MIN_OST,
CY_ABS_OR_OST,
CY_NUM_ABS_OST /* number of abs signals */
};
enum cyttsp4_flags {
CY_FLAG_NONE = 0x00,
CY_FLAG_HOVER = 0x04,
CY_FLAG_FLIP = 0x08,
CY_FLAG_INV_X = 0x10,
CY_FLAG_INV_Y = 0x20,
CY_FLAG_VKEYS = 0x40,
};
enum cyttsp4_object_id {
CY_OBJ_STANDARD_FINGER,
CY_OBJ_LARGE_OBJECT,
CY_OBJ_STYLUS,
CY_OBJ_HOVER,
};
enum cyttsp4_event_id {
CY_EV_NO_EVENT,
CY_EV_TOUCHDOWN,
CY_EV_MOVE, /* significant displacement (> act dist) */
CY_EV_LIFTOFF, /* record reports last position */
};
/* x-axis resolution of panel in pixels */
#define CY_PCFG_RESOLUTION_X_MASK 0x7F
/* y-axis resolution of panel in pixels */
#define CY_PCFG_RESOLUTION_Y_MASK 0x7F
/* x-axis, 0:origin is on left side of panel, 1: right */
#define CY_PCFG_ORIGIN_X_MASK 0x80
/* y-axis, 0:origin is on top side of panel, 1: bottom */
#define CY_PCFG_ORIGIN_Y_MASK 0x80
static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size,
void *buf)
{
return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
}
static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size,
const void *buf)
{
return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
}
extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
struct device *dev, u16 irq, size_t xfer_buf_size);
extern int cyttsp4_remove(struct cyttsp4 *ts);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
u8 length, const void *values);
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
u8 length, void *values);
extern const struct dev_pm_ops cyttsp4_pm_ops;
#endif /* _LINUX_CYTTSP4_CORE_H */

View file

@ -0,0 +1,90 @@
/*
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp4_core.h"
#include <linux/i2c.h>
#include <linux/input.h>
#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
.read = cyttsp_i2c_read_block_data,
};
static int cyttsp4_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cyttsp4 *ts;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "I2C functionality not Supported\n");
return -EIO;
}
ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
CYTTSP4_I2C_DATA_SIZE);
if (IS_ERR(ts))
return PTR_ERR(ts);
return 0;
}
static int cyttsp4_i2c_remove(struct i2c_client *client)
{
struct cyttsp4 *ts = i2c_get_clientdata(client);
cyttsp4_remove(ts);
return 0;
}
static const struct i2c_device_id cyttsp4_i2c_id[] = {
{ CYTTSP4_I2C_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
static struct i2c_driver cyttsp4_i2c_driver = {
.driver = {
.name = CYTTSP4_I2C_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp4_pm_ops,
},
.probe = cyttsp4_i2c_probe,
.remove = cyttsp4_i2c_remove,
.id_table = cyttsp4_i2c_id,
};
module_i2c_driver(cyttsp4_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("i2c:cyttsp4");

View file

@ -0,0 +1,205 @@
/*
* Source for:
* Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
* For use with Cypress Txx4xx parts.
* Supported parts include:
* TMA4XX
* TMA1036
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include "cyttsp4_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_BITS_PER_WORD 8
#define CY_SPI_A8_BIT 0x02
#define CY_SPI_WR_HEADER_BYTES 2
#define CY_SPI_RD_HEADER_BYTES 1
#define CY_SPI_CMD_BYTES 2
#define CY_SPI_SYNC_BYTE 0
#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
#define CY_SPI_DATA_SIZE (2 * 256)
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u8 reg, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
u8 *wr_buf = &xfer_buf[0];
u8 rd_buf[CY_SPI_CMD_BYTES];
int retval;
int i;
if (length > CY_SPI_DATA_SIZE) {
dev_err(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_CMD_BYTES);
if (reg > 255)
wr_buf[0] = op + CY_SPI_A8_BIT;
else
wr_buf[0] = op;
if (op == CY_SPI_WR_OP)
wr_buf[1] = reg % 256;
if (op == CY_SPI_WR_OP && length > 0)
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_RD_HEADER_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(dev, "%s: bad operation code=%d\n", __func__, op);
return -EINVAL;
}
retval = spi_sync(spi, &msg);
if (retval < 0) {
dev_dbg(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_ACK) {
dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
__func__, i, rd_buf[i]);
for (i = 0; i < length; i++)
dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
}
return 0;
}
static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, void *data)
{
int rc;
rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
if (rc)
return rc;
else
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
length);
}
static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, const void *data)
{
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
length);
}
static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
.bustype = BUS_SPI,
.write = cyttsp_spi_write_block_data,
.read = cyttsp_spi_read_block_data,
};
static int cyttsp4_spi_probe(struct spi_device *spi)
{
struct cyttsp4 *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 = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
CY_SPI_DATA_BUF_SIZE);
if (IS_ERR(ts))
return PTR_ERR(ts);
return 0;
}
static int cyttsp4_spi_remove(struct spi_device *spi)
{
struct cyttsp4 *ts = spi_get_drvdata(spi);
cyttsp4_remove(ts);
return 0;
}
static struct spi_driver cyttsp4_spi_driver = {
.driver = {
.name = CYTTSP4_SPI_NAME,
.owner = THIS_MODULE,
.pm = &cyttsp4_pm_ops,
},
.probe = cyttsp4_spi_probe,
.remove = cyttsp4_spi_remove,
};
module_spi_driver(cyttsp4_spi_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
MODULE_AUTHOR("Cypress");
MODULE_ALIAS("spi:cyttsp4");

View file

@ -84,7 +84,8 @@ static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
error = ts->bus_ops->read(ts, command, length, buf);
error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command,
length, buf);
if (!error)
return 0;
@ -101,7 +102,8 @@ static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
error = ts->bus_ops->write(ts, command, length, buf);
error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command,
length, buf);
if (!error)
return 0;

View file

@ -112,9 +112,10 @@ 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);
int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
const void *values);
int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
void *values);
};
enum cyttsp_state {
@ -144,6 +145,10 @@ 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);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
u8 length, const void *values);
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */

View file

@ -1,5 +1,5 @@
/*
* Source for:
* cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx3xx parts.
* Supported parts include:
@ -19,11 +19,7 @@
* 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>
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
@ -34,47 +30,6 @@
#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,
@ -98,7 +53,6 @@ static int cyttsp_i2c_probe(struct i2c_client *client,
return PTR_ERR(ts);
i2c_set_clientdata(client, ts);
return 0;
}

View file

@ -0,0 +1,79 @@
/*
* cyttsp_i2c_common.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx3xx and Txx4xx parts.
* Supported parts include:
* CY8CTST341
* CY8CTMA340
* TMA4XX
* TMA1036
*
* 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.
*
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
#include <linux/device.h>
#include <linux/export.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/types.h>
int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, void *values)
{
struct i2c_client *client = to_i2c_client(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;
}
EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, const void *values)
{
struct i2c_client *client = to_i2c_client(dev);
int retval;
xfer_buf[0] = addr;
memcpy(&xfer_buf[1], values, length);
retval = i2c_master_send(client, xfer_buf, length + 1);
return retval < 0 ? retval : 0;
}
EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cypress");

View file

@ -8,6 +8,7 @@
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
* Copyright (C) 2013 Cypress Semiconductor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,11 +20,7 @@
* 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>
* Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
@ -43,19 +40,19 @@
#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,
static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u8 reg, u8 *buf, int length)
{
struct spi_device *spi = to_spi_device(ts->dev);
struct spi_device *spi = to_spi_device(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];
u8 *wr_buf = &xfer_buf[0];
u8 *rd_buf = &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",
dev_err(dev, "%s: length %d is too big.\n",
__func__, length);
return -EINVAL;
}
@ -95,13 +92,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
break;
default:
dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
dev_err(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",
dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
__func__, retval, xfer[1].len, op);
/*
@ -113,14 +110,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
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);
dev_dbg(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",
dev_dbg(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",
dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
@ -129,16 +125,18 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
return 0;
}
static int cyttsp_spi_read_block_data(struct cyttsp *ts,
static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, void *data)
{
return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
length);
}
static int cyttsp_spi_write_block_data(struct cyttsp *ts,
static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, const void *data)
{
return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
length);
}
static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {

View file

@ -329,8 +329,6 @@ static int da9052_ts_remove(struct platform_device *pdev)
input_unregister_device(tsi->dev);
kfree(tsi);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -166,24 +166,22 @@ static int egalax_firmware_version(struct i2c_client *client)
}
static int egalax_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
const struct i2c_device_id *id)
{
struct egalax_ts *ts;
struct input_dev *input_dev;
int ret;
int error;
ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL);
ts = devm_kzalloc(&client->dev, sizeof(struct egalax_ts), GFP_KERNEL);
if (!ts) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
input_dev = input_allocate_device();
input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
error = -ENOMEM;
goto err_free_ts;
return -ENOMEM;
}
ts->client = client;
@ -193,19 +191,17 @@ static int egalax_ts_probe(struct i2c_client *client,
error = egalax_wake_up_device(client);
if (error) {
dev_err(&client->dev, "Failed to wake up the controller\n");
goto err_free_dev;
return error;
}
ret = egalax_firmware_version(client);
if (ret < 0) {
error = egalax_firmware_version(client);
if (error < 0) {
dev_err(&client->dev, "Failed to read firmware version\n");
error = -EIO;
goto err_free_dev;
return error;
}
input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
@ -221,41 +217,21 @@ static int egalax_ts_probe(struct i2c_client *client,
input_set_drvdata(input_dev, ts);
error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"egalax_ts", ts);
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
egalax_ts_interrupt,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"egalax_ts", ts);
if (error < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
goto err_free_dev;
return error;
}
error = input_register_device(ts->input_dev);
if (error)
goto err_free_irq;
return error;
i2c_set_clientdata(client, ts);
return 0;
err_free_irq:
free_irq(client->irq, ts);
err_free_dev:
input_free_device(input_dev);
err_free_ts:
kfree(ts);
return error;
}
static int egalax_ts_remove(struct i2c_client *client)
{
struct egalax_ts *ts = i2c_get_clientdata(client);
free_irq(client->irq, ts);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
static const struct i2c_device_id egalax_ts_id[] = {
@ -301,7 +277,6 @@ static struct i2c_driver egalax_ts_driver = {
},
.id_table = egalax_ts_id,
.probe = egalax_ts_probe,
.remove = egalax_ts_remove,
};
module_i2c_driver(egalax_ts_driver);

View file

@ -651,8 +651,6 @@ static int mrstouch_remove(struct platform_device *pdev)
input_unregister_device(tsdev->input);
kfree(tsdev);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -145,7 +145,6 @@ static int jornada720_ts_probe(struct platform_device *pdev)
fail2:
free_irq(IRQ_GPIO9, pdev);
fail1:
platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(jornada_ts);
return error;
@ -156,7 +155,6 @@ static int jornada720_ts_remove(struct platform_device *pdev)
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO9, pdev);
platform_set_drvdata(pdev, NULL);
input_unregister_device(jornada_ts->dev);
kfree(jornada_ts);

View file

@ -233,8 +233,6 @@ static int mc13783_ts_remove(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
destroy_workqueue(priv->workq);
input_unregister_device(priv->idev);
kfree(priv);

View file

@ -336,7 +336,6 @@ static int titsc_remove(struct platform_device *pdev)
input_unregister_device(ts_dev->input);
platform_set_drvdata(pdev, NULL);
kfree(ts_dev);
return 0;
}

View file

@ -351,7 +351,6 @@ error_clk:
error_map:
release_mem_region(ts->res->start, resource_size(ts->res));
error_res:
platform_set_drvdata(pdev, NULL);
kfree(ts);
return error;
@ -366,7 +365,6 @@ static int tsc_remove(struct platform_device *pdev)
clk_put(ts->clk);
iounmap(ts->regs);
release_mem_region(ts->res->start, resource_size(ts->res));
platform_set_drvdata(pdev, NULL);
kfree(ts);
return 0;

View file

@ -17,6 +17,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
@ -38,20 +39,13 @@ struct ts_event {
};
struct tps6507x_ts {
struct input_dev *input_dev;
struct device *dev;
char phys[32];
struct delayed_work work;
unsigned polling; /* polling is active */
struct ts_event tc;
struct input_polled_dev *poll_dev;
struct tps6507x_dev *mfd;
u16 model;
unsigned pendown;
int irq;
void (*clear_penirq)(void);
unsigned long poll_period; /* ms */
char phys[32];
struct ts_event tc;
u16 min_pressure;
int vref; /* non-zero to leave vref on */
bool pendown;
};
static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
@ -161,18 +155,15 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
return ret;
}
static void tps6507x_ts_handler(struct work_struct *work)
static void tps6507x_ts_poll(struct input_polled_dev *poll_dev)
{
struct tps6507x_ts *tsc = container_of(work,
struct tps6507x_ts, work.work);
struct input_dev *input_dev = tsc->input_dev;
int pendown;
int schd;
int poll = 0;
struct tps6507x_ts *tsc = poll_dev->private;
struct input_dev *input_dev = poll_dev->input;
bool pendown;
s32 ret;
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
&tsc->tc.pressure);
ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
&tsc->tc.pressure);
if (ret)
goto done;
@ -183,7 +174,7 @@ static void tps6507x_ts_handler(struct work_struct *work)
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
tsc->pendown = 0;
tsc->pendown = false;
}
if (pendown) {
@ -208,76 +199,69 @@ static void tps6507x_ts_handler(struct work_struct *work)
input_report_abs(input_dev, ABS_Y, tsc->tc.y);
input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
input_sync(input_dev);
tsc->pendown = 1;
poll = 1;
tsc->pendown = true;
}
done:
/* always poll if not using interrupts */
poll = 1;
if (poll) {
schd = schedule_delayed_work(&tsc->work,
msecs_to_jiffies(tsc->poll_period));
if (schd)
tsc->polling = 1;
else {
tsc->polling = 0;
dev_err(tsc->dev, "re-schedule failed");
}
} else
tsc->polling = 0;
ret = tps6507x_adc_standby(tsc);
tps6507x_adc_standby(tsc);
}
static int tps6507x_ts_probe(struct platform_device *pdev)
{
int error;
struct tps6507x_ts *tsc;
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
struct touchscreen_init_data *init_data;
const struct tps6507x_board *tps_board;
const struct touchscreen_init_data *init_data;
struct tps6507x_ts *tsc;
struct input_polled_dev *poll_dev;
struct input_dev *input_dev;
struct tps6507x_board *tps_board;
int schd;
int error;
/**
/*
* tps_board points to pmic related constants
* coming from the board-evm file.
*/
tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data;
tps_board = dev_get_platdata(tps6507x_dev->dev);
if (!tps_board) {
dev_err(tps6507x_dev->dev,
"Could not find tps6507x platform data\n");
return -EIO;
return -ENODEV;
}
/**
/*
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
init_data = tps_board->tps6507x_ts_init_data;
tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
if (!tsc) {
dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
error = -ENOMEM;
goto err0;
return -ENOMEM;
}
tps6507x_dev->ts = tsc;
tsc->mfd = tps6507x_dev;
tsc->dev = tps6507x_dev->dev;
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(tsc->dev, "Failed to allocate input device.\n");
tsc->min_pressure = init_data ?
init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE;
snprintf(tsc->phys, sizeof(tsc->phys),
"%s/input0", dev_name(tsc->dev));
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
dev_err(tsc->dev, "Failed to allocate polled input device.\n");
error = -ENOMEM;
goto err1;
goto err_free_mem;
}
tsc->poll_dev = poll_dev;
poll_dev->private = tsc;
poll_dev->poll = tps6507x_ts_poll;
poll_dev->poll_interval = init_data ?
init_data->poll_period : TSC_DEFAULT_POLL_PERIOD;
input_dev = poll_dev->input;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
@ -286,76 +270,42 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
input_dev->name = "TPS6507x Touchscreen";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = tsc->dev;
snprintf(tsc->phys, sizeof(tsc->phys),
"%s/input0", dev_name(tsc->dev));
input_dev->phys = tsc->phys;
dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
input_set_drvdata(input_dev, tsc);
tsc->input_dev = input_dev;
INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
input_dev->dev.parent = tsc->dev;
input_dev->id.bustype = BUS_I2C;
if (init_data) {
tsc->poll_period = init_data->poll_period;
tsc->vref = init_data->vref;
tsc->min_pressure = init_data->min_pressure;
input_dev->id.vendor = init_data->vendor;
input_dev->id.product = init_data->product;
input_dev->id.version = init_data->version;
} else {
tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
}
error = tps6507x_adc_standby(tsc);
if (error)
goto err2;
goto err_free_polled_dev;
error = input_register_device(input_dev);
error = input_register_polled_device(poll_dev);
if (error)
goto err2;
goto err_free_polled_dev;
schd = schedule_delayed_work(&tsc->work,
msecs_to_jiffies(tsc->poll_period));
if (schd)
tsc->polling = 1;
else {
tsc->polling = 0;
dev_err(tsc->dev, "schedule failed");
goto err2;
}
platform_set_drvdata(pdev, tps6507x_dev);
platform_set_drvdata(pdev, tsc);
return 0;
err2:
cancel_delayed_work_sync(&tsc->work);
input_free_device(input_dev);
err1:
err_free_polled_dev:
input_free_polled_device(poll_dev);
err_free_mem:
kfree(tsc);
tps6507x_dev->ts = NULL;
err0:
return error;
}
static int tps6507x_ts_remove(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
struct tps6507x_ts *tsc = tps6507x_dev->ts;
struct input_dev *input_dev = tsc->input_dev;
struct tps6507x_ts *tsc = platform_get_drvdata(pdev);
struct input_polled_dev *poll_dev = tsc->poll_dev;
cancel_delayed_work_sync(&tsc->work);
input_unregister_polled_device(poll_dev);
input_free_polled_device(poll_dev);
input_unregister_device(input_dev);
tps6507x_dev->ts = NULL;
kfree(tsc);
return 0;

View file

@ -318,8 +318,6 @@ static int w90x900ts_remove(struct platform_device *pdev)
input_unregister_device(w90p910_ts->input);
kfree(w90p910_ts);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -1,7 +1,7 @@
/*
* Wacom Penabled Driver for I2C
*
* Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
* Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom.
* <tobita.tatsunosuke@wacom.co.jp>
*
* This program is free software; you can redistribute it
@ -27,7 +27,6 @@
#define WACOM_CMD_THROW0 0x05
#define WACOM_CMD_THROW1 0x00
#define WACOM_QUERY_SIZE 19
#define WACOM_RETRY_CNT 100
struct wacom_features {
int x_max;
@ -40,6 +39,8 @@ struct wacom_i2c {
struct i2c_client *client;
struct input_dev *input;
u8 data[WACOM_QUERY_SIZE];
bool prox;
int tool;
};
static int wacom_query_device(struct i2c_client *client,
@ -112,9 +113,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
if (!wac_i2c->prox)
wac_i2c->tool = (data[3] & 0x0c) ?
BTN_TOOL_RUBBER : BTN_TOOL_PEN;
wac_i2c->prox = data[3] & 0x20;
input_report_key(input, BTN_TOUCH, tsw || ers);
input_report_key(input, BTN_TOOL_PEN, tsw);
input_report_key(input, BTN_TOOL_RUBBER, ers);
input_report_key(input, wac_i2c->tool, wac_i2c->prox);
input_report_key(input, BTN_STYLUS, f1);
input_report_key(input, BTN_STYLUS2, f2);
input_report_abs(input, ABS_X, x);

Some files were not shown because too many files have changed in this diff Show more