forked from Minki/linux
Merge branch 'next' into for-linus
Prepare first round of input updates for 4.2 merge window.
This commit is contained in:
commit
f7ebc4dcde
@ -19,8 +19,7 @@ adi,adt7475 +/-1C TDM Extended Temp Range I.C
|
|||||||
adi,adt7476 +/-1C TDM Extended Temp Range I.C
|
adi,adt7476 +/-1C TDM Extended Temp Range I.C
|
||||||
adi,adt7490 +/-1C TDM Extended Temp Range I.C
|
adi,adt7490 +/-1C TDM Extended Temp Range I.C
|
||||||
adi,adxl345 Three-Axis Digital Accelerometer
|
adi,adxl345 Three-Axis Digital Accelerometer
|
||||||
adi,adxl346 Three-Axis Digital Accelerometer
|
adi,adxl346 Three-Axis Digital Accelerometer (backward-compatibility value "adi,adxl345" must be listed too)
|
||||||
adi,adxl34x Three-Axis Digital Accelerometer
|
|
||||||
at,24c08 i2c serial eeprom (24cxx)
|
at,24c08 i2c serial eeprom (24cxx)
|
||||||
atmel,24c00 i2c serial eeprom (24cxx)
|
atmel,24c00 i2c serial eeprom (24cxx)
|
||||||
atmel,24c01 i2c serial eeprom (24cxx)
|
atmel,24c01 i2c serial eeprom (24cxx)
|
||||||
|
17
Documentation/devicetree/bindings/input/ti,drv2665.txt
Normal file
17
Documentation/devicetree/bindings/input/ti,drv2665.txt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
* Texas Instruments - drv2665 Haptics driver
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible - "ti,drv2665" - DRV2665
|
||||||
|
- reg - I2C slave address
|
||||||
|
- vbat-supply - Required supply regulator
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
haptics: haptics@59 {
|
||||||
|
compatible = "ti,drv2665";
|
||||||
|
reg = <0x59>;
|
||||||
|
vbat-supply = <&vbat>;
|
||||||
|
};
|
||||||
|
|
||||||
|
For more product information please see the link below:
|
||||||
|
http://www.ti.com/product/drv2665
|
@ -2,9 +2,6 @@
|
|||||||
LED handling under Linux
|
LED handling under Linux
|
||||||
========================
|
========================
|
||||||
|
|
||||||
If you're reading this and thinking about keyboard leds, these are
|
|
||||||
handled by the input subsystem and the led class is *not* needed.
|
|
||||||
|
|
||||||
In its simplest form, the LED class just allows control of LEDs from
|
In its simplest form, the LED class just allows control of LEDs from
|
||||||
userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
|
userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
|
||||||
LED is defined in max_brightness file. The brightness file will set the brightness
|
LED is defined in max_brightness file. The brightness file will set the brightness
|
||||||
|
@ -5043,7 +5043,6 @@ F: include/linux/input/
|
|||||||
INPUT MULTITOUCH (MT) PROTOCOL
|
INPUT MULTITOUCH (MT) PROTOCOL
|
||||||
M: Henrik Rydberg <rydberg@bitmath.org>
|
M: Henrik Rydberg <rydberg@bitmath.org>
|
||||||
L: linux-input@vger.kernel.org
|
L: linux-input@vger.kernel.org
|
||||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
|
|
||||||
S: Odd fixes
|
S: Odd fixes
|
||||||
F: Documentation/input/multi-touch-protocol.txt
|
F: Documentation/input/multi-touch-protocol.txt
|
||||||
F: drivers/input/input-mt.c
|
F: drivers/input/input-mt.c
|
||||||
|
@ -25,6 +25,19 @@ config INPUT
|
|||||||
|
|
||||||
if INPUT
|
if INPUT
|
||||||
|
|
||||||
|
config INPUT_LEDS
|
||||||
|
tristate "Export input device LEDs in sysfs"
|
||||||
|
depends on LEDS_CLASS
|
||||||
|
default INPUT
|
||||||
|
help
|
||||||
|
Say Y here if you would like to export LEDs on input devices
|
||||||
|
as standard LED class devices in sysfs.
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called input-leds.
|
||||||
|
|
||||||
config INPUT_FF_MEMLESS
|
config INPUT_FF_MEMLESS
|
||||||
tristate "Support for memoryless force-feedback devices"
|
tristate "Support for memoryless force-feedback devices"
|
||||||
help
|
help
|
||||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
|
|||||||
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
|
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
|
||||||
obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
|
obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_INPUT_LEDS) += input-leds.o
|
||||||
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
|
||||||
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
|
||||||
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
|
||||||
|
@ -422,10 +422,7 @@ static int evdev_release(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
evdev_detach_client(evdev, client);
|
evdev_detach_client(evdev, client);
|
||||||
|
|
||||||
if (is_vmalloc_addr(client))
|
kvfree(client);
|
||||||
vfree(client);
|
|
||||||
else
|
|
||||||
kfree(client);
|
|
||||||
|
|
||||||
evdev_close_device(evdev);
|
evdev_close_device(evdev);
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* calculate manginude of sine wave as average of rumble's
|
* calculate magnitude of sine wave as average of rumble's
|
||||||
* 2/3 of strong magnitude and 1/3 of weak magnitude
|
* 2/3 of strong magnitude and 1/3 of weak magnitude
|
||||||
*/
|
*/
|
||||||
magnitude = effect->u.rumble.strong_magnitude / 3 +
|
magnitude = effect->u.rumble.strong_magnitude / 3 +
|
||||||
@ -213,7 +213,7 @@ static int erase_effect(struct input_dev *dev, int effect_id,
|
|||||||
/**
|
/**
|
||||||
* input_ff_erase - erase a force-feedback effect from device
|
* input_ff_erase - erase a force-feedback effect from device
|
||||||
* @dev: input device to erase effect from
|
* @dev: input device to erase effect from
|
||||||
* @effect_id: id of the ffect to be erased
|
* @effect_id: id of the effect to be erased
|
||||||
* @file: purported owner of the request
|
* @file: purported owner of the request
|
||||||
*
|
*
|
||||||
* This function erases a force-feedback effect from specified device.
|
* This function erases a force-feedback effect from specified device.
|
||||||
|
212
drivers/input/input-leds.c
Normal file
212
drivers/input/input-leds.c
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* LED support for the input layer
|
||||||
|
*
|
||||||
|
* Copyright 2010-2015 Samuel Thibault <samuel.thibault@ens-lyon.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 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_VT)
|
||||||
|
#define VT_TRIGGER(_name) .trigger = _name
|
||||||
|
#else
|
||||||
|
#define VT_TRIGGER(_name) .trigger = NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct {
|
||||||
|
const char *name;
|
||||||
|
const char *trigger;
|
||||||
|
} input_led_info[LED_CNT] = {
|
||||||
|
[LED_NUML] = { "numlock", VT_TRIGGER("kbd-numlock") },
|
||||||
|
[LED_CAPSL] = { "capslock", VT_TRIGGER("kbd-capslock") },
|
||||||
|
[LED_SCROLLL] = { "scrolllock", VT_TRIGGER("kbd-scrolllock") },
|
||||||
|
[LED_COMPOSE] = { "compose" },
|
||||||
|
[LED_KANA] = { "kana", VT_TRIGGER("kbd-kanalock") },
|
||||||
|
[LED_SLEEP] = { "sleep" } ,
|
||||||
|
[LED_SUSPEND] = { "suspend" },
|
||||||
|
[LED_MUTE] = { "mute" },
|
||||||
|
[LED_MISC] = { "misc" },
|
||||||
|
[LED_MAIL] = { "mail" },
|
||||||
|
[LED_CHARGING] = { "charging" },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_led {
|
||||||
|
struct led_classdev cdev;
|
||||||
|
struct input_handle *handle;
|
||||||
|
unsigned int code; /* One of LED_* constants */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_leds {
|
||||||
|
struct input_handle handle;
|
||||||
|
unsigned int num_leds;
|
||||||
|
struct input_led leds[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum led_brightness input_leds_brightness_get(struct led_classdev *cdev)
|
||||||
|
{
|
||||||
|
struct input_led *led = container_of(cdev, struct input_led, cdev);
|
||||||
|
struct input_dev *input = led->handle->dev;
|
||||||
|
|
||||||
|
return test_bit(led->code, input->led) ? cdev->max_brightness : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_leds_brightness_set(struct led_classdev *cdev,
|
||||||
|
enum led_brightness brightness)
|
||||||
|
{
|
||||||
|
struct input_led *led = container_of(cdev, struct input_led, cdev);
|
||||||
|
|
||||||
|
input_inject_event(led->handle, EV_LED, led->code, !!brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_leds_event(struct input_handle *handle, unsigned int type,
|
||||||
|
unsigned int code, int value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int input_leds_connect(struct input_handler *handler,
|
||||||
|
struct input_dev *dev,
|
||||||
|
const struct input_device_id *id)
|
||||||
|
{
|
||||||
|
struct input_leds *leds;
|
||||||
|
unsigned int num_leds;
|
||||||
|
unsigned int led_code;
|
||||||
|
int led_no;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
num_leds = bitmap_weight(dev->ledbit, LED_CNT);
|
||||||
|
if (!num_leds)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
leds = kzalloc(sizeof(*leds) + num_leds * sizeof(*leds->leds),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!leds)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
leds->num_leds = num_leds;
|
||||||
|
|
||||||
|
leds->handle.dev = dev;
|
||||||
|
leds->handle.handler = handler;
|
||||||
|
leds->handle.name = "leds";
|
||||||
|
leds->handle.private = leds;
|
||||||
|
|
||||||
|
error = input_register_handle(&leds->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_free_mem;
|
||||||
|
|
||||||
|
error = input_open_device(&leds->handle);
|
||||||
|
if (error)
|
||||||
|
goto err_unregister_handle;
|
||||||
|
|
||||||
|
led_no = 0;
|
||||||
|
for_each_set_bit(led_code, dev->ledbit, LED_CNT) {
|
||||||
|
struct input_led *led = &leds->leds[led_no];
|
||||||
|
|
||||||
|
led->handle = &leds->handle;
|
||||||
|
led->code = led_code;
|
||||||
|
|
||||||
|
if (WARN_ON(!input_led_info[led_code].name))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
|
||||||
|
dev_name(&dev->dev),
|
||||||
|
input_led_info[led_code].name);
|
||||||
|
if (!led->cdev.name) {
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto err_unregister_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
led->cdev.max_brightness = 1;
|
||||||
|
led->cdev.brightness_get = input_leds_brightness_get;
|
||||||
|
led->cdev.brightness_set = input_leds_brightness_set;
|
||||||
|
led->cdev.default_trigger = input_led_info[led_code].trigger;
|
||||||
|
|
||||||
|
error = led_classdev_register(&dev->dev, &led->cdev);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&dev->dev, "failed to register LED %s: %d\n",
|
||||||
|
led->cdev.name, error);
|
||||||
|
kfree(led->cdev.name);
|
||||||
|
goto err_unregister_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
led_no++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_unregister_leds:
|
||||||
|
while (--led_no >= 0) {
|
||||||
|
struct input_led *led = &leds->leds[led_no];
|
||||||
|
|
||||||
|
led_classdev_unregister(&led->cdev);
|
||||||
|
kfree(led->cdev.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_close_device(&leds->handle);
|
||||||
|
|
||||||
|
err_unregister_handle:
|
||||||
|
input_unregister_handle(&leds->handle);
|
||||||
|
|
||||||
|
err_free_mem:
|
||||||
|
kfree(leds);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_leds_disconnect(struct input_handle *handle)
|
||||||
|
{
|
||||||
|
struct input_leds *leds = handle->private;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < leds->num_leds; i++) {
|
||||||
|
struct input_led *led = &leds->leds[i];
|
||||||
|
|
||||||
|
led_classdev_unregister(&led->cdev);
|
||||||
|
kfree(led->cdev.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_close_device(handle);
|
||||||
|
input_unregister_handle(handle);
|
||||||
|
|
||||||
|
kfree(leds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct input_device_id input_leds_ids[] = {
|
||||||
|
{
|
||||||
|
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
|
||||||
|
.evbit = { BIT_MASK(EV_LED) },
|
||||||
|
},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(input, input_leds_ids);
|
||||||
|
|
||||||
|
static struct input_handler input_leds_handler = {
|
||||||
|
.event = input_leds_event,
|
||||||
|
.connect = input_leds_connect,
|
||||||
|
.disconnect = input_leds_disconnect,
|
||||||
|
.name = "leds",
|
||||||
|
.id_table = input_leds_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init input_leds_init(void)
|
||||||
|
{
|
||||||
|
return input_register_handler(&input_leds_handler);
|
||||||
|
}
|
||||||
|
module_init(input_leds_init);
|
||||||
|
|
||||||
|
static void __exit input_leds_exit(void)
|
||||||
|
{
|
||||||
|
input_unregister_handler(&input_leds_handler);
|
||||||
|
}
|
||||||
|
module_exit(input_leds_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Samuel Thibault <samuel.thibault@ens-lyon.org>");
|
||||||
|
MODULE_AUTHOR("Dmitry Torokhov <dmitry.torokhov@gmail.com>");
|
||||||
|
MODULE_DESCRIPTION("Input -> LEDs Bridge");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -2262,7 +2262,7 @@ EXPORT_SYMBOL(input_unregister_handler);
|
|||||||
*
|
*
|
||||||
* Iterate over @bus's list of devices, and call @fn for each, passing
|
* Iterate over @bus's list of devices, and call @fn for each, passing
|
||||||
* it @data and stop when @fn returns a non-zero value. The function is
|
* it @data and stop when @fn returns a non-zero value. The function is
|
||||||
* using RCU to traverse the list and therefore may be usind in atonic
|
* using RCU to traverse the list and therefore may be using in atomic
|
||||||
* contexts. The @fn callback is invoked from RCU critical section and
|
* contexts. The @fn callback is invoked from RCU critical section and
|
||||||
* thus must not sleep.
|
* thus must not sleep.
|
||||||
*/
|
*/
|
||||||
|
@ -367,6 +367,7 @@ config KEYBOARD_MAPLE
|
|||||||
|
|
||||||
config KEYBOARD_MAX7359
|
config KEYBOARD_MAX7359
|
||||||
tristate "Maxim MAX7359 Key Switch Controller"
|
tristate "Maxim MAX7359 Key Switch Controller"
|
||||||
|
select INPUT_MATRIXKMAP
|
||||||
depends on I2C
|
depends on I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the Maxim MAX7359 Key
|
If you say yes here you get support for the Maxim MAX7359 Key
|
||||||
|
@ -180,7 +180,7 @@
|
|||||||
#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
|
#define LOGIC2_STAT (1 << 7) /* ADP5589 only */
|
||||||
#define LOGIC1_STAT (1 << 6)
|
#define LOGIC1_STAT (1 << 6)
|
||||||
#define LOCK_STAT (1 << 5) /* ADP5589 only */
|
#define LOCK_STAT (1 << 5) /* ADP5589 only */
|
||||||
#define KEC 0xF
|
#define KEC 0x1F
|
||||||
|
|
||||||
/* PIN_CONFIG_D Register */
|
/* PIN_CONFIG_D Register */
|
||||||
#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
|
#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
|
||||||
@ -726,7 +726,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
|
|||||||
|
|
||||||
pull_mask |= val << (2 * (i & 0x3));
|
pull_mask |= val << (2 * (i & 0x3));
|
||||||
|
|
||||||
if (i == 3 || i == kpad->var->max_row_num) {
|
if (i % 4 == 3 || i == kpad->var->max_row_num) {
|
||||||
ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
|
ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
|
||||||
+ (i >> 2), pull_mask);
|
+ (i >> 2), pull_mask);
|
||||||
pull_mask = 0;
|
pull_mask = 0;
|
||||||
@ -746,7 +746,7 @@ static int adp5589_setup(struct adp5589_kpad *kpad)
|
|||||||
|
|
||||||
pull_mask |= val << (2 * (i & 0x3));
|
pull_mask |= val << (2 * (i & 0x3));
|
||||||
|
|
||||||
if (i == 3 || i == kpad->var->max_col_num) {
|
if (i % 4 == 3 || i == kpad->var->max_col_num) {
|
||||||
ret |= adp5589_write(client,
|
ret |= adp5589_write(client,
|
||||||
reg(ADP5585_RPULL_CONFIG_C) +
|
reg(ADP5585_RPULL_CONFIG_C) +
|
||||||
(i >> 2), pull_mask);
|
(i >> 2), pull_mask);
|
||||||
|
@ -120,14 +120,9 @@ static int clps711x_keypad_probe(struct platform_device *pdev)
|
|||||||
for (i = 0; i < priv->row_count; i++) {
|
for (i = 0; i < priv->row_count; i++) {
|
||||||
struct clps711x_gpio_data *data = &priv->gpio_data[i];
|
struct clps711x_gpio_data *data = &priv->gpio_data[i];
|
||||||
|
|
||||||
data->desc = devm_gpiod_get_index(dev, "row", i);
|
data->desc = devm_gpiod_get_index(dev, "row", i, GPIOD_IN);
|
||||||
if (!data->desc)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (IS_ERR(data->desc))
|
if (IS_ERR(data->desc))
|
||||||
return PTR_ERR(data->desc);
|
return PTR_ERR(data->desc);
|
||||||
|
|
||||||
gpiod_direction_input(data->desc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = of_property_read_u32(np, "poll-interval", &poll_interval);
|
err = of_property_read_u32(np, "poll-interval", &poll_interval);
|
||||||
|
@ -84,26 +84,6 @@ static int max7359_read_reg(struct i2c_client *client, int reg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void max7359_build_keycode(struct max7359_keypad *keypad,
|
|
||||||
const struct matrix_keymap_data *keymap_data)
|
|
||||||
{
|
|
||||||
struct input_dev *input_dev = keypad->input_dev;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < keymap_data->keymap_size; i++) {
|
|
||||||
unsigned int key = keymap_data->keymap[i];
|
|
||||||
unsigned int row = KEY_ROW(key);
|
|
||||||
unsigned int col = KEY_COL(key);
|
|
||||||
unsigned int scancode = MATRIX_SCAN_CODE(row, col,
|
|
||||||
MAX7359_ROW_SHIFT);
|
|
||||||
unsigned short keycode = KEY_VAL(key);
|
|
||||||
|
|
||||||
keypad->keycodes[scancode] = keycode;
|
|
||||||
__set_bit(keycode, input_dev->keybit);
|
|
||||||
}
|
|
||||||
__clear_bit(KEY_RESERVED, input_dev->keybit);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* runs in an IRQ thread -- can (and will!) sleep */
|
/* runs in an IRQ thread -- can (and will!) sleep */
|
||||||
static irqreturn_t max7359_interrupt(int irq, void *dev_id)
|
static irqreturn_t max7359_interrupt(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
@ -166,7 +146,6 @@ static void max7359_close(struct input_dev *dev)
|
|||||||
static void max7359_initialize(struct i2c_client *client)
|
static void max7359_initialize(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
max7359_write_reg(client, MAX7359_REG_CONFIG,
|
max7359_write_reg(client, MAX7359_REG_CONFIG,
|
||||||
MAX7359_CFG_INTERRUPT | /* Irq clears after host read */
|
|
||||||
MAX7359_CFG_KEY_RELEASE | /* Key release enable */
|
MAX7359_CFG_KEY_RELEASE | /* Key release enable */
|
||||||
MAX7359_CFG_WAKEUP); /* Key press wakeup enable */
|
MAX7359_CFG_WAKEUP); /* Key press wakeup enable */
|
||||||
|
|
||||||
@ -233,7 +212,15 @@ static int max7359_probe(struct i2c_client *client,
|
|||||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||||
input_set_drvdata(input_dev, keypad);
|
input_set_drvdata(input_dev, keypad);
|
||||||
|
|
||||||
max7359_build_keycode(keypad, keymap_data);
|
error = matrix_keypad_build_keymap(keymap_data, NULL,
|
||||||
|
MAX7359_MAX_KEY_ROWS,
|
||||||
|
MAX7359_MAX_KEY_COLS,
|
||||||
|
keypad->keycodes,
|
||||||
|
input_dev);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "failed to build keymap\n");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
|
||||||
max7359_interrupt,
|
max7359_interrupt,
|
||||||
|
@ -585,7 +585,7 @@ static const struct of_device_id samsung_keypad_dt_match[] = {
|
|||||||
MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
|
MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_device_id samsung_keypad_driver_ids[] = {
|
static const struct platform_device_id samsung_keypad_driver_ids[] = {
|
||||||
{
|
{
|
||||||
.name = "samsung-keypad",
|
.name = "samsung-keypad",
|
||||||
.driver_data = KEYPAD_TYPE_SAMSUNG,
|
.driver_data = KEYPAD_TYPE_SAMSUNG,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* Based on omap-keypad driver
|
* Based on omap-keypad driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010 ST Microelectronics
|
* Copyright (C) 2010 ST Microelectronics
|
||||||
* Rajeev Kumar<rajeev-dlh.kumar@st.com>
|
* Rajeev Kumar <rajeevkumar.linux@gmail.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under the terms of the GNU General Public
|
* This file is licensed under the terms of the GNU General Public
|
||||||
* License version 2. This program is licensed "as is" without any
|
* License version 2. This program is licensed "as is" without any
|
||||||
|
@ -610,6 +610,16 @@ config INPUT_DA9055_ONKEY
|
|||||||
To compile this driver as a module, choose M here: the module
|
To compile this driver as a module, choose M here: the module
|
||||||
will be called da9055_onkey.
|
will be called da9055_onkey.
|
||||||
|
|
||||||
|
config INPUT_DA9063_ONKEY
|
||||||
|
tristate "Dialog DA9063 OnKey"
|
||||||
|
depends on MFD_DA9063
|
||||||
|
help
|
||||||
|
Support the ONKEY of Dialog DA9063 Power Management IC as an
|
||||||
|
input device reporting power button statue.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called da9063_onkey.
|
||||||
|
|
||||||
config INPUT_DM355EVM
|
config INPUT_DM355EVM
|
||||||
tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
|
tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
|
||||||
depends on MFD_DM355EVM_MSP
|
depends on MFD_DM355EVM_MSP
|
||||||
@ -775,6 +785,17 @@ config INPUT_DRV260X_HAPTICS
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called drv260x-haptics.
|
module will be called drv260x-haptics.
|
||||||
|
|
||||||
|
config INPUT_DRV2665_HAPTICS
|
||||||
|
tristate "TI DRV2665 haptics support"
|
||||||
|
depends on INPUT && I2C
|
||||||
|
select INPUT_FF_MEMLESS
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
Say Y to enable support for the TI DRV2665 haptics driver.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called drv2665-haptics.
|
||||||
|
|
||||||
config INPUT_DRV2667_HAPTICS
|
config INPUT_DRV2667_HAPTICS
|
||||||
tristate "TI DRV2667 haptics support"
|
tristate "TI DRV2667 haptics support"
|
||||||
depends on INPUT && I2C
|
depends on INPUT && I2C
|
||||||
@ -784,6 +805,6 @@ config INPUT_DRV2667_HAPTICS
|
|||||||
Say Y to enable support for the TI DRV2667 haptics driver.
|
Say Y to enable support for the TI DRV2667 haptics driver.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called drv260x-haptics.
|
module will be called drv2667-haptics.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
@ -25,9 +25,11 @@ obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
|
|||||||
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
|
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
|
||||||
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
|
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
|
||||||
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
|
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
|
||||||
|
obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o
|
||||||
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
|
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
|
||||||
obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
|
obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
|
||||||
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
|
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
|
||||||
|
obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
|
||||||
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
|
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
|
||||||
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
|
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
|
||||||
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
|
obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/input.h> /* BUS_I2C */
|
#include <linux/input.h> /* BUS_I2C */
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include "adxl34x.h"
|
#include "adxl34x.h"
|
||||||
@ -135,11 +136,31 @@ static const struct i2c_device_id adxl34x_id[] = {
|
|||||||
|
|
||||||
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
|
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id adxl34x_of_id[] = {
|
||||||
|
/*
|
||||||
|
* The ADXL346 is backward-compatible with the ADXL345. Differences are
|
||||||
|
* handled by runtime detection of the device model, there's thus no
|
||||||
|
* need for listing the "adi,adxl346" compatible value explicitly.
|
||||||
|
*/
|
||||||
|
{ .compatible = "adi,adxl345", },
|
||||||
|
/*
|
||||||
|
* Deprecated, DT nodes should use one or more of the device-specific
|
||||||
|
* compatible values "adi,adxl345" and "adi,adxl346".
|
||||||
|
*/
|
||||||
|
{ .compatible = "adi,adxl34x", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, adxl34x_of_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct i2c_driver adxl34x_driver = {
|
static struct i2c_driver adxl34x_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "adxl34x",
|
.name = "adxl34x",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pm = &adxl34x_i2c_pm,
|
.pm = &adxl34x_i2c_pm,
|
||||||
|
.of_match_table = of_match_ptr(adxl34x_of_id),
|
||||||
},
|
},
|
||||||
.probe = adxl34x_i2c_probe,
|
.probe = adxl34x_i2c_probe,
|
||||||
.remove = adxl34x_i2c_remove,
|
.remove = adxl34x_i2c_remove,
|
||||||
|
226
drivers/input/misc/da9063_onkey.c
Normal file
226
drivers/input/misc/da9063_onkey.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
* OnKey device driver for DA9063
|
||||||
|
* Copyright (C) 2015 Dialog Semiconductor Ltd.
|
||||||
|
*
|
||||||
|
* 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/errno.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/mfd/da9063/core.h>
|
||||||
|
#include <linux/mfd/da9063/pdata.h>
|
||||||
|
#include <linux/mfd/da9063/registers.h>
|
||||||
|
|
||||||
|
struct da9063_onkey {
|
||||||
|
struct da9063 *hw;
|
||||||
|
struct delayed_work work;
|
||||||
|
struct input_dev *input;
|
||||||
|
struct device *dev;
|
||||||
|
bool key_power;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void da9063_poll_on(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct da9063_onkey *onkey = container_of(work, struct da9063_onkey,
|
||||||
|
work.work);
|
||||||
|
unsigned int val;
|
||||||
|
int fault_log = 0;
|
||||||
|
bool poll = true;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Poll to see when the pin is released */
|
||||||
|
error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
|
||||||
|
if (error) {
|
||||||
|
dev_err(onkey->dev,
|
||||||
|
"Failed to read ON status: %d\n", error);
|
||||||
|
goto err_poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(val & DA9063_NONKEY)) {
|
||||||
|
error = regmap_update_bits(onkey->hw->regmap,
|
||||||
|
DA9063_REG_CONTROL_B,
|
||||||
|
DA9063_NONKEY_LOCK, 0);
|
||||||
|
if (error) {
|
||||||
|
dev_err(onkey->dev,
|
||||||
|
"Failed to reset the Key Delay %d\n", error);
|
||||||
|
goto err_poll;
|
||||||
|
}
|
||||||
|
|
||||||
|
input_report_key(onkey->input, KEY_POWER, 0);
|
||||||
|
input_sync(onkey->input);
|
||||||
|
|
||||||
|
poll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the fault log KEY_RESET is detected, then clear it
|
||||||
|
* and shut down the system.
|
||||||
|
*/
|
||||||
|
error = regmap_read(onkey->hw->regmap,
|
||||||
|
DA9063_REG_FAULT_LOG, &fault_log);
|
||||||
|
if (error) {
|
||||||
|
dev_warn(&onkey->input->dev,
|
||||||
|
"Cannot read FAULT_LOG: %d\n", error);
|
||||||
|
} else if (fault_log & DA9063_KEY_RESET) {
|
||||||
|
error = regmap_write(onkey->hw->regmap,
|
||||||
|
DA9063_REG_FAULT_LOG,
|
||||||
|
DA9063_KEY_RESET);
|
||||||
|
if (error) {
|
||||||
|
dev_warn(&onkey->input->dev,
|
||||||
|
"Cannot reset KEY_RESET fault log: %d\n",
|
||||||
|
error);
|
||||||
|
} else {
|
||||||
|
/* at this point we do any S/W housekeeping
|
||||||
|
* and then send shutdown command
|
||||||
|
*/
|
||||||
|
dev_dbg(&onkey->input->dev,
|
||||||
|
"Sending SHUTDOWN to DA9063 ...\n");
|
||||||
|
error = regmap_write(onkey->hw->regmap,
|
||||||
|
DA9063_REG_CONTROL_F,
|
||||||
|
DA9063_SHUTDOWN);
|
||||||
|
if (error)
|
||||||
|
dev_err(&onkey->input->dev,
|
||||||
|
"Cannot SHUTDOWN DA9063: %d\n",
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err_poll:
|
||||||
|
if (poll)
|
||||||
|
schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct da9063_onkey *onkey = data;
|
||||||
|
unsigned int val;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val);
|
||||||
|
if (onkey->key_power && !error && (val & DA9063_NONKEY)) {
|
||||||
|
input_report_key(onkey->input, KEY_POWER, 1);
|
||||||
|
input_sync(onkey->input);
|
||||||
|
schedule_delayed_work(&onkey->work, 0);
|
||||||
|
dev_dbg(onkey->dev, "KEY_POWER pressed.\n");
|
||||||
|
} else {
|
||||||
|
input_report_key(onkey->input, KEY_SLEEP, 1);
|
||||||
|
input_sync(onkey->input);
|
||||||
|
input_report_key(onkey->input, KEY_SLEEP, 0);
|
||||||
|
input_sync(onkey->input);
|
||||||
|
dev_dbg(onkey->dev, "KEY_SLEEP pressed.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void da9063_cancel_poll(void *data)
|
||||||
|
{
|
||||||
|
struct da9063_onkey *onkey = data;
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&onkey->work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int da9063_onkey_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct da9063_pdata *pdata = dev_get_platdata(da9063->dev);
|
||||||
|
struct da9063_onkey *onkey;
|
||||||
|
int irq;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!onkey) {
|
||||||
|
dev_err(&pdev->dev, "Failed to allocate memory.\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
onkey->dev = &pdev->dev;
|
||||||
|
onkey->hw = da9063;
|
||||||
|
|
||||||
|
if (pdata)
|
||||||
|
onkey->key_power = pdata->key_power;
|
||||||
|
else
|
||||||
|
onkey->key_power =
|
||||||
|
!of_property_read_bool(pdev->dev.of_node,
|
||||||
|
"dlg,disable-key-power");
|
||||||
|
|
||||||
|
onkey->input = devm_input_allocate_device(&pdev->dev);
|
||||||
|
if (!onkey->input) {
|
||||||
|
dev_err(&pdev->dev, "Failed to allocated input device.\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
onkey->input->name = DA9063_DRVNAME_ONKEY;
|
||||||
|
onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0";
|
||||||
|
onkey->input->dev.parent = &pdev->dev;
|
||||||
|
|
||||||
|
if (onkey->key_power)
|
||||||
|
input_set_capability(onkey->input, EV_KEY, KEY_POWER);
|
||||||
|
|
||||||
|
input_set_capability(onkey->input, EV_KEY, KEY_SLEEP);
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
|
||||||
|
|
||||||
|
error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to add cancel poll action: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
irq = platform_get_irq_byname(pdev, "ONKEY");
|
||||||
|
if (irq < 0) {
|
||||||
|
error = irq;
|
||||||
|
dev_err(&pdev->dev, "Failed to get platform IRQ: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = devm_request_threaded_irq(&pdev->dev, irq,
|
||||||
|
NULL, da9063_onkey_irq_handler,
|
||||||
|
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||||
|
"ONKEY", onkey);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to request IRQ %d: %d\n", irq, error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = input_register_device(onkey->input);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Failed to register input device: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, onkey);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver da9063_onkey_driver = {
|
||||||
|
.probe = da9063_onkey_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = DA9063_DRVNAME_ONKEY,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(da9063_onkey_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
|
||||||
|
MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
|
@ -580,15 +580,10 @@ static int drv260x_probe(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
haptics->enable_gpio = devm_gpiod_get(&client->dev, "enable");
|
haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
|
||||||
if (IS_ERR(haptics->enable_gpio)) {
|
GPIOD_OUT_HIGH);
|
||||||
error = PTR_ERR(haptics->enable_gpio);
|
if (IS_ERR(haptics->enable_gpio))
|
||||||
if (error != -ENOENT && error != -ENOSYS)
|
return PTR_ERR(haptics->enable_gpio);
|
||||||
return error;
|
|
||||||
haptics->enable_gpio = NULL;
|
|
||||||
} else {
|
|
||||||
gpiod_direction_output(haptics->enable_gpio, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
haptics->input_dev = devm_input_allocate_device(&client->dev);
|
haptics->input_dev = devm_input_allocate_device(&client->dev);
|
||||||
if (!haptics->input_dev) {
|
if (!haptics->input_dev) {
|
||||||
|
322
drivers/input/misc/drv2665.c
Normal file
322
drivers/input/misc/drv2665.c
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* DRV2665 haptics driver family
|
||||||
|
*
|
||||||
|
* Author: Dan Murphy <dmurphy@ti.com>
|
||||||
|
*
|
||||||
|
* Copyright: (C) 2015 Texas Instruments, Inc.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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/i2c.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
|
/* Contol registers */
|
||||||
|
#define DRV2665_STATUS 0x00
|
||||||
|
#define DRV2665_CTRL_1 0x01
|
||||||
|
#define DRV2665_CTRL_2 0x02
|
||||||
|
#define DRV2665_FIFO 0x0b
|
||||||
|
|
||||||
|
/* Status Register */
|
||||||
|
#define DRV2665_FIFO_FULL BIT(0)
|
||||||
|
#define DRV2665_FIFO_EMPTY BIT(1)
|
||||||
|
|
||||||
|
/* Control 1 Register */
|
||||||
|
#define DRV2665_25_VPP_GAIN 0x00
|
||||||
|
#define DRV2665_50_VPP_GAIN 0x01
|
||||||
|
#define DRV2665_75_VPP_GAIN 0x02
|
||||||
|
#define DRV2665_100_VPP_GAIN 0x03
|
||||||
|
#define DRV2665_DIGITAL_IN 0xfc
|
||||||
|
#define DRV2665_ANALOG_IN BIT(2)
|
||||||
|
|
||||||
|
/* Control 2 Register */
|
||||||
|
#define DRV2665_BOOST_EN BIT(1)
|
||||||
|
#define DRV2665_STANDBY BIT(6)
|
||||||
|
#define DRV2665_DEV_RST BIT(7)
|
||||||
|
#define DRV2665_5_MS_IDLE_TOUT 0x00
|
||||||
|
#define DRV2665_10_MS_IDLE_TOUT 0x04
|
||||||
|
#define DRV2665_15_MS_IDLE_TOUT 0x08
|
||||||
|
#define DRV2665_20_MS_IDLE_TOUT 0x0c
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct drv2665_data -
|
||||||
|
* @input_dev - Pointer to the input device
|
||||||
|
* @client - Pointer to the I2C client
|
||||||
|
* @regmap - Register map of the device
|
||||||
|
* @work - Work item used to off load the enable/disable of the vibration
|
||||||
|
* @regulator - Pointer to the regulator for the IC
|
||||||
|
*/
|
||||||
|
struct drv2665_data {
|
||||||
|
struct input_dev *input_dev;
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct work_struct work;
|
||||||
|
struct regulator *regulator;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 8kHz Sine wave to stream to the FIFO */
|
||||||
|
static const u8 drv2665_sine_wave_form[] = {
|
||||||
|
0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66,
|
||||||
|
0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10,
|
||||||
|
0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a,
|
||||||
|
0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct reg_default drv2665_reg_defs[] = {
|
||||||
|
{ DRV2665_STATUS, 0x02 },
|
||||||
|
{ DRV2665_CTRL_1, 0x28 },
|
||||||
|
{ DRV2665_CTRL_2, 0x40 },
|
||||||
|
{ DRV2665_FIFO, 0x00 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drv2665_worker(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics =
|
||||||
|
container_of(work, struct drv2665_data, work);
|
||||||
|
unsigned int read_buf;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = regmap_read(haptics->regmap, DRV2665_STATUS, &read_buf);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&haptics->client->dev,
|
||||||
|
"Failed to read status: %d\n", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_buf & DRV2665_FIFO_EMPTY) {
|
||||||
|
error = regmap_bulk_write(haptics->regmap,
|
||||||
|
DRV2665_FIFO,
|
||||||
|
drv2665_sine_wave_form,
|
||||||
|
ARRAY_SIZE(drv2665_sine_wave_form));
|
||||||
|
if (error) {
|
||||||
|
dev_err(&haptics->client->dev,
|
||||||
|
"Failed to write FIFO: %d\n", error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int drv2665_haptics_play(struct input_dev *input, void *data,
|
||||||
|
struct ff_effect *effect)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics = input_get_drvdata(input);
|
||||||
|
|
||||||
|
schedule_work(&haptics->work);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drv2665_close(struct input_dev *input)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics = input_get_drvdata(input);
|
||||||
|
int error;
|
||||||
|
|
||||||
|
cancel_work_sync(&haptics->work);
|
||||||
|
|
||||||
|
error = regmap_update_bits(haptics->regmap,
|
||||||
|
DRV2665_CTRL_2, DRV2665_STANDBY, 1);
|
||||||
|
if (error)
|
||||||
|
dev_err(&haptics->client->dev,
|
||||||
|
"Failed to enter standby mode: %d\n", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct reg_default drv2665_init_regs[] = {
|
||||||
|
{ DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
|
||||||
|
{ DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int drv2665_init(struct drv2665_data *haptics)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
error = regmap_register_patch(haptics->regmap,
|
||||||
|
drv2665_init_regs,
|
||||||
|
ARRAY_SIZE(drv2665_init_regs));
|
||||||
|
if (error) {
|
||||||
|
dev_err(&haptics->client->dev,
|
||||||
|
"Failed to write init registers: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct regmap_config drv2665_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
|
||||||
|
.max_register = DRV2665_FIFO,
|
||||||
|
.reg_defaults = drv2665_reg_defs,
|
||||||
|
.num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs),
|
||||||
|
.cache_type = REGCACHE_NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int drv2665_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
|
||||||
|
if (!haptics)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
haptics->regulator = devm_regulator_get(&client->dev, "vbat");
|
||||||
|
if (IS_ERR(haptics->regulator)) {
|
||||||
|
error = PTR_ERR(haptics->regulator);
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"unable to get regulator, error: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
haptics->input_dev = devm_input_allocate_device(&client->dev);
|
||||||
|
if (!haptics->input_dev) {
|
||||||
|
dev_err(&client->dev, "Failed to allocate input device\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
haptics->input_dev->name = "drv2665:haptics";
|
||||||
|
haptics->input_dev->dev.parent = client->dev.parent;
|
||||||
|
haptics->input_dev->close = drv2665_close;
|
||||||
|
input_set_drvdata(haptics->input_dev, haptics);
|
||||||
|
input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
|
||||||
|
|
||||||
|
error = input_ff_create_memless(haptics->input_dev, NULL,
|
||||||
|
drv2665_haptics_play);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "input_ff_create() failed: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIT_WORK(&haptics->work, drv2665_worker);
|
||||||
|
|
||||||
|
haptics->client = client;
|
||||||
|
i2c_set_clientdata(client, haptics);
|
||||||
|
|
||||||
|
haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config);
|
||||||
|
if (IS_ERR(haptics->regmap)) {
|
||||||
|
error = PTR_ERR(haptics->regmap);
|
||||||
|
dev_err(&client->dev, "Failed to allocate register map: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = drv2665_init(haptics);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "Device init failed: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = input_register_device(haptics->input_dev);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "couldn't register input device: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused drv2665_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics = dev_get_drvdata(dev);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&haptics->input_dev->mutex);
|
||||||
|
|
||||||
|
if (haptics->input_dev->users) {
|
||||||
|
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
|
||||||
|
DRV2665_STANDBY, 1);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to set standby mode\n");
|
||||||
|
regulator_disable(haptics->regulator);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regulator_disable(haptics->regulator);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to disable regulator\n");
|
||||||
|
regmap_update_bits(haptics->regmap,
|
||||||
|
DRV2665_CTRL_2,
|
||||||
|
DRV2665_STANDBY, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
mutex_unlock(&haptics->input_dev->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused drv2665_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct drv2665_data *haptics = dev_get_drvdata(dev);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
mutex_lock(&haptics->input_dev->mutex);
|
||||||
|
|
||||||
|
if (haptics->input_dev->users) {
|
||||||
|
ret = regulator_enable(haptics->regulator);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to enable regulator\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
|
||||||
|
DRV2665_STANDBY, 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Failed to unset standby mode\n");
|
||||||
|
regulator_disable(haptics->regulator);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
mutex_unlock(&haptics->input_dev->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
|
||||||
|
|
||||||
|
static const struct i2c_device_id drv2665_id[] = {
|
||||||
|
{ "drv2665", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, drv2665_id);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id drv2665_of_match[] = {
|
||||||
|
{ .compatible = "ti,drv2665", },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, drv2665_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct i2c_driver drv2665_driver = {
|
||||||
|
.probe = drv2665_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "drv2665-haptics",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(drv2665_of_match),
|
||||||
|
.pm = &drv2665_pm_ops,
|
||||||
|
},
|
||||||
|
.id_table = drv2665_id,
|
||||||
|
};
|
||||||
|
module_i2c_driver(drv2665_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("TI DRV2665 haptics driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
|
@ -66,13 +66,12 @@ static int gpio_beeper_probe(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct gpio_beeper *beep;
|
struct gpio_beeper *beep;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
int err;
|
|
||||||
|
|
||||||
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
|
beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
|
||||||
if (!beep)
|
if (!beep)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
beep->desc = devm_gpiod_get(&pdev->dev, NULL);
|
beep->desc = devm_gpiod_get(&pdev->dev, NULL, GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(beep->desc))
|
if (IS_ERR(beep->desc))
|
||||||
return PTR_ERR(beep->desc);
|
return PTR_ERR(beep->desc);
|
||||||
|
|
||||||
@ -92,10 +91,6 @@ static int gpio_beeper_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
input_set_capability(input, EV_SND, SND_BELL);
|
input_set_capability(input, EV_SND, SND_BELL);
|
||||||
|
|
||||||
err = gpiod_direction_output(beep->desc, 0);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
input_set_drvdata(input, beep);
|
input_set_drvdata(input, beep);
|
||||||
|
|
||||||
return input_register_device(input);
|
return input_register_device(input);
|
||||||
|
@ -63,7 +63,8 @@ static int retu_pwrbutton_probe(struct platform_device *pdev)
|
|||||||
input_set_drvdata(idev, rdev);
|
input_set_drvdata(idev, rdev);
|
||||||
|
|
||||||
error = devm_request_threaded_irq(&pdev->dev, irq,
|
error = devm_request_threaded_irq(&pdev->dev, irq,
|
||||||
NULL, retu_pwrbutton_irq, 0,
|
NULL, retu_pwrbutton_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
"retu-pwrbutton", idev);
|
"retu-pwrbutton", idev);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
#include <linux/gpio_keys.h>
|
#include <linux/gpio_keys.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/acpi.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Definition of buttons on the tablet. The ACPI index of each button
|
* Definition of buttons on the tablet. The ACPI index of each button
|
||||||
|
@ -71,7 +71,8 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev)
|
|||||||
pwr->dev.parent = &pdev->dev;
|
pwr->dev.parent = &pdev->dev;
|
||||||
|
|
||||||
err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,
|
err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq,
|
||||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
|
||||||
|
IRQF_ONESHOT,
|
||||||
"twl4030_pwrbutton", pwr);
|
"twl4030_pwrbutton", pwr);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
|
dev_err(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err);
|
||||||
|
@ -308,7 +308,8 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
|
|||||||
mutex_init(&info->mutex);
|
mutex_init(&info->mutex);
|
||||||
|
|
||||||
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
|
||||||
twl6040_vib_irq_handler, 0,
|
twl6040_vib_irq_handler,
|
||||||
|
IRQF_ONESHOT,
|
||||||
"twl6040_irq_vib", info);
|
"twl6040_irq_vib", info);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
|
dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
|
||||||
|
@ -99,7 +99,8 @@ static int wm831x_on_probe(struct platform_device *pdev)
|
|||||||
wm831x_on->dev->dev.parent = &pdev->dev;
|
wm831x_on->dev->dev.parent = &pdev->dev;
|
||||||
|
|
||||||
ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
|
ret = request_threaded_irq(irq, NULL, wm831x_on_irq,
|
||||||
IRQF_TRIGGER_RISING, "wm831x_on",
|
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||||
|
"wm831x_on",
|
||||||
wm831x_on);
|
wm831x_on);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
|
dev_err(&pdev->dev, "Unable to request IRQ: %d\n", ret);
|
||||||
|
@ -159,8 +159,8 @@ static const struct alps_protocol_info alps_v8_protocol_data = {
|
|||||||
|
|
||||||
static void alps_set_abs_params_st(struct alps_data *priv,
|
static void alps_set_abs_params_st(struct alps_data *priv,
|
||||||
struct input_dev *dev1);
|
struct input_dev *dev1);
|
||||||
static void alps_set_abs_params_mt(struct alps_data *priv,
|
static void alps_set_abs_params_semi_mt(struct alps_data *priv,
|
||||||
struct input_dev *dev1);
|
struct input_dev *dev1);
|
||||||
static void alps_set_abs_params_v7(struct alps_data *priv,
|
static void alps_set_abs_params_v7(struct alps_data *priv,
|
||||||
struct input_dev *dev1);
|
struct input_dev *dev1);
|
||||||
static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
|
static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
|
||||||
@ -310,53 +310,6 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
|
|||||||
input_sync(dev);
|
input_sync(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Process bitmap data for V5 protocols. Return value is null.
|
|
||||||
*
|
|
||||||
* The bitmaps don't have enough data to track fingers, so this function
|
|
||||||
* only generates points representing a bounding box of at most two contacts.
|
|
||||||
* These two points are returned in fields->mt.
|
|
||||||
*/
|
|
||||||
static void alps_process_bitmap_dolphin(struct alps_data *priv,
|
|
||||||
struct alps_fields *fields)
|
|
||||||
{
|
|
||||||
int box_middle_x, box_middle_y;
|
|
||||||
unsigned int x_map, y_map;
|
|
||||||
unsigned char start_bit, end_bit;
|
|
||||||
unsigned char x_msb, x_lsb, y_msb, y_lsb;
|
|
||||||
|
|
||||||
x_map = fields->x_map;
|
|
||||||
y_map = fields->y_map;
|
|
||||||
|
|
||||||
if (!x_map || !y_map)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Get Most-significant and Least-significant bit */
|
|
||||||
x_msb = fls(x_map);
|
|
||||||
x_lsb = ffs(x_map);
|
|
||||||
y_msb = fls(y_map);
|
|
||||||
y_lsb = ffs(y_map);
|
|
||||||
|
|
||||||
/* Most-significant bit should never exceed max sensor line number */
|
|
||||||
if (x_msb > priv->x_bits || y_msb > priv->y_bits)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (fields->fingers > 1) {
|
|
||||||
start_bit = priv->x_bits - x_msb;
|
|
||||||
end_bit = priv->x_bits - x_lsb;
|
|
||||||
box_middle_x = (priv->x_max * (start_bit + end_bit)) /
|
|
||||||
(2 * (priv->x_bits - 1));
|
|
||||||
|
|
||||||
start_bit = y_lsb - 1;
|
|
||||||
end_bit = y_msb - 1;
|
|
||||||
box_middle_y = (priv->y_max * (start_bit + end_bit)) /
|
|
||||||
(2 * (priv->y_bits - 1));
|
|
||||||
fields->mt[0] = fields->st;
|
|
||||||
fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
|
|
||||||
fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void alps_get_bitmap_points(unsigned int map,
|
static void alps_get_bitmap_points(unsigned int map,
|
||||||
struct alps_bitmap_point *low,
|
struct alps_bitmap_point *low,
|
||||||
struct alps_bitmap_point *high,
|
struct alps_bitmap_point *high,
|
||||||
@ -384,7 +337,7 @@ static void alps_get_bitmap_points(unsigned int map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process bitmap data from v3 and v4 protocols. Returns the number of
|
* Process bitmap data from semi-mt protocols. Returns the number of
|
||||||
* fingers detected. A return value of 0 means at least one of the
|
* fingers detected. A return value of 0 means at least one of the
|
||||||
* bitmaps was empty.
|
* bitmaps was empty.
|
||||||
*
|
*
|
||||||
@ -396,9 +349,10 @@ static void alps_get_bitmap_points(unsigned int map,
|
|||||||
static int alps_process_bitmap(struct alps_data *priv,
|
static int alps_process_bitmap(struct alps_data *priv,
|
||||||
struct alps_fields *fields)
|
struct alps_fields *fields)
|
||||||
{
|
{
|
||||||
int i, fingers_x = 0, fingers_y = 0, fingers;
|
int i, fingers_x = 0, fingers_y = 0, fingers, closest;
|
||||||
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
|
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
|
||||||
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
|
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
|
||||||
|
struct input_mt_pos corner[4];
|
||||||
|
|
||||||
if (!fields->x_map || !fields->y_map)
|
if (!fields->x_map || !fields->y_map)
|
||||||
return 0;
|
return 0;
|
||||||
@ -429,26 +383,76 @@ static int alps_process_bitmap(struct alps_data *priv,
|
|||||||
y_high.num_bits = max(i, 1);
|
y_high.num_bits = max(i, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fields->mt[0].x =
|
/* top-left corner */
|
||||||
|
corner[0].x =
|
||||||
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
|
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
|
||||||
(2 * (priv->x_bits - 1));
|
(2 * (priv->x_bits - 1));
|
||||||
fields->mt[0].y =
|
corner[0].y =
|
||||||
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
|
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
|
||||||
(2 * (priv->y_bits - 1));
|
(2 * (priv->y_bits - 1));
|
||||||
|
|
||||||
fields->mt[1].x =
|
/* top-right corner */
|
||||||
|
corner[1].x =
|
||||||
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
|
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
|
||||||
(2 * (priv->x_bits - 1));
|
(2 * (priv->x_bits - 1));
|
||||||
fields->mt[1].y =
|
corner[1].y =
|
||||||
|
(priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
|
||||||
|
(2 * (priv->y_bits - 1));
|
||||||
|
|
||||||
|
/* bottom-right corner */
|
||||||
|
corner[2].x =
|
||||||
|
(priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
|
||||||
|
(2 * (priv->x_bits - 1));
|
||||||
|
corner[2].y =
|
||||||
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
|
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
|
||||||
(2 * (priv->y_bits - 1));
|
(2 * (priv->y_bits - 1));
|
||||||
|
|
||||||
/* y-bitmap order is reversed, except on rushmore */
|
/* bottom-left corner */
|
||||||
if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
|
corner[3].x =
|
||||||
fields->mt[0].y = priv->y_max - fields->mt[0].y;
|
(priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
|
||||||
fields->mt[1].y = priv->y_max - fields->mt[1].y;
|
(2 * (priv->x_bits - 1));
|
||||||
|
corner[3].y =
|
||||||
|
(priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
|
||||||
|
(2 * (priv->y_bits - 1));
|
||||||
|
|
||||||
|
/* x-bitmap order is reversed on v5 touchpads */
|
||||||
|
if (priv->proto_version == ALPS_PROTO_V5) {
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
corner[i].x = priv->x_max - corner[i].x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* y-bitmap order is reversed on v3 and v4 touchpads */
|
||||||
|
if (priv->proto_version == ALPS_PROTO_V3 ||
|
||||||
|
priv->proto_version == ALPS_PROTO_V4) {
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
corner[i].y = priv->y_max - corner[i].y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only select a corner for the second touch once per 2 finger
|
||||||
|
* touch sequence to avoid the chosen corner (and thus the coordinates)
|
||||||
|
* jumping around when the first touch is in the middle.
|
||||||
|
*/
|
||||||
|
if (priv->second_touch == -1) {
|
||||||
|
/* Find corner closest to our st coordinates */
|
||||||
|
closest = 0x7fffffff;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
int dx = fields->st.x - corner[i].x;
|
||||||
|
int dy = fields->st.y - corner[i].y;
|
||||||
|
int distance = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
if (distance < closest) {
|
||||||
|
priv->second_touch = i;
|
||||||
|
closest = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* And select the opposite corner to use for the 2nd touch */
|
||||||
|
priv->second_touch = (priv->second_touch + 2) % 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields->mt[0] = fields->st;
|
||||||
|
fields->mt[1] = corner[priv->second_touch];
|
||||||
|
|
||||||
return fingers;
|
return fingers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,9 +489,14 @@ static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
|
|||||||
f->mt[0].x = f->st.x;
|
f->mt[0].x = f->st.x;
|
||||||
f->mt[0].y = f->st.y;
|
f->mt[0].y = f->st.y;
|
||||||
fingers = f->pressure > 0 ? 1 : 0;
|
fingers = f->pressure > 0 ? 1 : 0;
|
||||||
|
priv->second_touch = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
|
if (fingers >= 1)
|
||||||
|
alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y);
|
||||||
|
if (fingers >= 2)
|
||||||
|
alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y);
|
||||||
|
input_mt_sync_frame(dev);
|
||||||
|
|
||||||
input_mt_report_finger_count(dev, fingers);
|
input_mt_report_finger_count(dev, fingers);
|
||||||
|
|
||||||
@ -584,20 +593,22 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
|
|||||||
f->first_mp = !!(p[4] & 0x40);
|
f->first_mp = !!(p[4] & 0x40);
|
||||||
f->is_mp = !!(p[0] & 0x40);
|
f->is_mp = !!(p[0] & 0x40);
|
||||||
|
|
||||||
f->fingers = (p[5] & 0x3) + 1;
|
if (f->is_mp) {
|
||||||
f->x_map = ((p[4] & 0x7e) << 8) |
|
f->fingers = (p[5] & 0x3) + 1;
|
||||||
((p[1] & 0x7f) << 2) |
|
f->x_map = ((p[4] & 0x7e) << 8) |
|
||||||
((p[0] & 0x30) >> 4);
|
((p[1] & 0x7f) << 2) |
|
||||||
f->y_map = ((p[3] & 0x70) << 4) |
|
((p[0] & 0x30) >> 4);
|
||||||
((p[2] & 0x7f) << 1) |
|
f->y_map = ((p[3] & 0x70) << 4) |
|
||||||
(p[4] & 0x01);
|
((p[2] & 0x7f) << 1) |
|
||||||
|
(p[4] & 0x01);
|
||||||
|
} else {
|
||||||
|
f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
|
||||||
|
((p[0] & 0x30) >> 4);
|
||||||
|
f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
|
||||||
|
f->pressure = p[5] & 0x7f;
|
||||||
|
|
||||||
f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
|
alps_decode_buttons_v3(f, p);
|
||||||
((p[0] & 0x30) >> 4);
|
}
|
||||||
f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
|
|
||||||
f->pressure = p[5] & 0x7f;
|
|
||||||
|
|
||||||
alps_decode_buttons_v3(f, p);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -605,13 +616,27 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
|
|||||||
static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
|
static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
|
||||||
struct psmouse *psmouse)
|
struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
alps_decode_pinnacle(f, p, psmouse);
|
f->first_mp = !!(p[4] & 0x40);
|
||||||
|
|
||||||
/* Rushmore's packet decode has a bit difference with Pinnacle's */
|
|
||||||
f->is_mp = !!(p[5] & 0x40);
|
f->is_mp = !!(p[5] & 0x40);
|
||||||
f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
|
|
||||||
f->x_map |= (p[5] & 0x10) << 11;
|
if (f->is_mp) {
|
||||||
f->y_map |= (p[5] & 0x20) << 6;
|
f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
|
||||||
|
f->x_map = ((p[5] & 0x10) << 11) |
|
||||||
|
((p[4] & 0x7e) << 8) |
|
||||||
|
((p[1] & 0x7f) << 2) |
|
||||||
|
((p[0] & 0x30) >> 4);
|
||||||
|
f->y_map = ((p[5] & 0x20) << 6) |
|
||||||
|
((p[3] & 0x70) << 4) |
|
||||||
|
((p[2] & 0x7f) << 1) |
|
||||||
|
(p[4] & 0x01);
|
||||||
|
} else {
|
||||||
|
f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
|
||||||
|
((p[0] & 0x30) >> 4);
|
||||||
|
f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
|
||||||
|
f->pressure = p[5] & 0x7f;
|
||||||
|
|
||||||
|
alps_decode_buttons_v3(f, p);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -680,30 +705,13 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
|
|||||||
*/
|
*/
|
||||||
if (f->is_mp) {
|
if (f->is_mp) {
|
||||||
fingers = f->fingers;
|
fingers = f->fingers;
|
||||||
if (priv->proto_version == ALPS_PROTO_V3 ||
|
/*
|
||||||
priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
|
* Bitmap processing uses position packet's coordinate
|
||||||
if (alps_process_bitmap(priv, f) == 0)
|
* data, so we need to do decode it first.
|
||||||
fingers = 0; /* Use st data */
|
*/
|
||||||
|
priv->decode_fields(f, priv->multi_data, psmouse);
|
||||||
/* Now process position packet */
|
if (alps_process_bitmap(priv, f) == 0)
|
||||||
priv->decode_fields(f, priv->multi_data,
|
fingers = 0; /* Use st data */
|
||||||
psmouse);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Because Dolphin uses position packet's
|
|
||||||
* coordinate data as Pt1 and uses it to
|
|
||||||
* calculate Pt2, so we need to do position
|
|
||||||
* packet decode first.
|
|
||||||
*/
|
|
||||||
priv->decode_fields(f, priv->multi_data,
|
|
||||||
psmouse);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since Dolphin's finger number is reliable,
|
|
||||||
* there is no need to compare with bmap_fn.
|
|
||||||
*/
|
|
||||||
alps_process_bitmap_dolphin(priv, f);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
priv->multi_packet = 0;
|
priv->multi_packet = 0;
|
||||||
}
|
}
|
||||||
@ -865,6 +873,14 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
|
|||||||
priv->multi_data[offset] = packet[6];
|
priv->multi_data[offset] = packet[6];
|
||||||
priv->multi_data[offset + 1] = packet[7];
|
priv->multi_data[offset + 1] = packet[7];
|
||||||
|
|
||||||
|
f->left = !!(packet[4] & 0x01);
|
||||||
|
f->right = !!(packet[4] & 0x02);
|
||||||
|
|
||||||
|
f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
|
||||||
|
((packet[0] & 0x30) >> 4);
|
||||||
|
f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
|
||||||
|
f->pressure = packet[5] & 0x7f;
|
||||||
|
|
||||||
if (++priv->multi_packet > 2) {
|
if (++priv->multi_packet > 2) {
|
||||||
priv->multi_packet = 0;
|
priv->multi_packet = 0;
|
||||||
|
|
||||||
@ -879,14 +895,6 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
|
|||||||
f->fingers = alps_process_bitmap(priv, f);
|
f->fingers = alps_process_bitmap(priv, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
f->left = !!(packet[4] & 0x01);
|
|
||||||
f->right = !!(packet[4] & 0x02);
|
|
||||||
|
|
||||||
f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
|
|
||||||
((packet[0] & 0x30) >> 4);
|
|
||||||
f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
|
|
||||||
f->pressure = packet[5] & 0x7f;
|
|
||||||
|
|
||||||
alps_report_semi_mt_data(psmouse, f->fingers);
|
alps_report_semi_mt_data(psmouse, f->fingers);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2561,7 +2569,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|||||||
case ALPS_PROTO_V3:
|
case ALPS_PROTO_V3:
|
||||||
priv->hw_init = alps_hw_init_v3;
|
priv->hw_init = alps_hw_init_v3;
|
||||||
priv->process_packet = alps_process_packet_v3;
|
priv->process_packet = alps_process_packet_v3;
|
||||||
priv->set_abs_params = alps_set_abs_params_mt;
|
priv->set_abs_params = alps_set_abs_params_semi_mt;
|
||||||
priv->decode_fields = alps_decode_pinnacle;
|
priv->decode_fields = alps_decode_pinnacle;
|
||||||
priv->nibble_commands = alps_v3_nibble_commands;
|
priv->nibble_commands = alps_v3_nibble_commands;
|
||||||
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
||||||
@ -2570,7 +2578,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|||||||
case ALPS_PROTO_V3_RUSHMORE:
|
case ALPS_PROTO_V3_RUSHMORE:
|
||||||
priv->hw_init = alps_hw_init_rushmore_v3;
|
priv->hw_init = alps_hw_init_rushmore_v3;
|
||||||
priv->process_packet = alps_process_packet_v3;
|
priv->process_packet = alps_process_packet_v3;
|
||||||
priv->set_abs_params = alps_set_abs_params_mt;
|
priv->set_abs_params = alps_set_abs_params_semi_mt;
|
||||||
priv->decode_fields = alps_decode_rushmore;
|
priv->decode_fields = alps_decode_rushmore;
|
||||||
priv->nibble_commands = alps_v3_nibble_commands;
|
priv->nibble_commands = alps_v3_nibble_commands;
|
||||||
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
||||||
@ -2586,7 +2594,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|||||||
case ALPS_PROTO_V4:
|
case ALPS_PROTO_V4:
|
||||||
priv->hw_init = alps_hw_init_v4;
|
priv->hw_init = alps_hw_init_v4;
|
||||||
priv->process_packet = alps_process_packet_v4;
|
priv->process_packet = alps_process_packet_v4;
|
||||||
priv->set_abs_params = alps_set_abs_params_mt;
|
priv->set_abs_params = alps_set_abs_params_semi_mt;
|
||||||
priv->nibble_commands = alps_v4_nibble_commands;
|
priv->nibble_commands = alps_v4_nibble_commands;
|
||||||
priv->addr_command = PSMOUSE_CMD_DISABLE;
|
priv->addr_command = PSMOUSE_CMD_DISABLE;
|
||||||
break;
|
break;
|
||||||
@ -2595,7 +2603,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
|||||||
priv->hw_init = alps_hw_init_dolphin_v1;
|
priv->hw_init = alps_hw_init_dolphin_v1;
|
||||||
priv->process_packet = alps_process_touchpad_packet_v3_v5;
|
priv->process_packet = alps_process_touchpad_packet_v3_v5;
|
||||||
priv->decode_fields = alps_decode_dolphin;
|
priv->decode_fields = alps_decode_dolphin;
|
||||||
priv->set_abs_params = alps_set_abs_params_mt;
|
priv->set_abs_params = alps_set_abs_params_semi_mt;
|
||||||
priv->nibble_commands = alps_v3_nibble_commands;
|
priv->nibble_commands = alps_v3_nibble_commands;
|
||||||
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
|
||||||
priv->x_bits = 23;
|
priv->x_bits = 23;
|
||||||
@ -2777,15 +2785,15 @@ static void alps_set_abs_params_mt_common(struct alps_data *priv,
|
|||||||
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
|
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alps_set_abs_params_mt(struct alps_data *priv,
|
static void alps_set_abs_params_semi_mt(struct alps_data *priv,
|
||||||
struct input_dev *dev1)
|
struct input_dev *dev1)
|
||||||
{
|
{
|
||||||
alps_set_abs_params_mt_common(priv, dev1);
|
alps_set_abs_params_mt_common(priv, dev1);
|
||||||
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
|
||||||
|
|
||||||
input_mt_init_slots(dev1, MAX_TOUCHES,
|
input_mt_init_slots(dev1, MAX_TOUCHES,
|
||||||
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
|
||||||
INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
|
INPUT_MT_SEMI_MT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alps_set_abs_params_v7(struct alps_data *priv,
|
static void alps_set_abs_params_v7(struct alps_data *priv,
|
||||||
|
@ -278,6 +278,7 @@ struct alps_data {
|
|||||||
|
|
||||||
int prev_fin;
|
int prev_fin;
|
||||||
int multi_packet;
|
int multi_packet;
|
||||||
|
int second_touch;
|
||||||
unsigned char multi_data[6];
|
unsigned char multi_data[6];
|
||||||
struct alps_fields f;
|
struct alps_fields f;
|
||||||
u8 quirks;
|
u8 quirks;
|
||||||
|
@ -950,14 +950,13 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
|
|||||||
* Device power mode can only be set when device is in operational mode.
|
* Device power mode can only be set when device is in operational mode.
|
||||||
*/
|
*/
|
||||||
static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
|
static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
|
||||||
u16 always_unused)
|
u16 always_unused)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u8 power;
|
u8 power;
|
||||||
int tries;
|
int tries;
|
||||||
u16 sleep_time;
|
u16 sleep_time;
|
||||||
|
|
||||||
always_unused = 0;
|
|
||||||
if (cyapa->state != CYAPA_STATE_OP)
|
if (cyapa->state != CYAPA_STATE_OP)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ struct gen5_app_cmd_head {
|
|||||||
u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
|
u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* Applicaton get/set parameter command data structure */
|
/* Application get/set parameter command data structure */
|
||||||
struct gen5_app_set_parameter_data {
|
struct gen5_app_set_parameter_data {
|
||||||
u8 parameter_id;
|
u8 parameter_id;
|
||||||
u8 parameter_size;
|
u8 parameter_size;
|
||||||
@ -832,7 +832,7 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
|
/* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
|
||||||
* 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
|
* 0x20 0x00 0xFF is Gen5 Bootloader HID Description Header.
|
||||||
*
|
*
|
||||||
* Must read HID Description content through out,
|
* Must read HID Description content through out,
|
||||||
* otherwise Gen5 trackpad cannot response next command
|
* otherwise Gen5 trackpad cannot response next command
|
||||||
@ -1654,8 +1654,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
|
|||||||
* that trackpad unable to report signal to wake system up
|
* that trackpad unable to report signal to wake system up
|
||||||
* in the special situation that system is in suspending, and
|
* in the special situation that system is in suspending, and
|
||||||
* at the same time, user touch trackpad to wake system up.
|
* at the same time, user touch trackpad to wake system up.
|
||||||
* This function can avoid the data to be buffured when system
|
* This function can avoid the data to be buffered when system
|
||||||
* is suspending which may cause interrput line unable to be
|
* is suspending which may cause interrupt line unable to be
|
||||||
* asserted again.
|
* asserted again.
|
||||||
*/
|
*/
|
||||||
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
|
cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
|
||||||
@ -2546,16 +2546,11 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
|
|||||||
gen5_pip->resp_sort_func(cyapa,
|
gen5_pip->resp_sort_func(cyapa,
|
||||||
gen5_pip->irq_cmd_buf, length))) {
|
gen5_pip->irq_cmd_buf, length))) {
|
||||||
/*
|
/*
|
||||||
* Cover the Gen5 V1 firmware issue.
|
* Work around the Gen5 V1 firmware
|
||||||
* The issue is there is no interrut will be
|
* that does not assert interrupt signalling
|
||||||
* asserted to notityf host to read a command
|
* that command response is ready if user
|
||||||
* data out when always has finger touch on
|
* keeps touching the trackpad while command
|
||||||
* trackpad during the command is issued to
|
* is sent to the device.
|
||||||
* trackad device.
|
|
||||||
* This issue has the scenario is that,
|
|
||||||
* user always has his fingers touched on
|
|
||||||
* trackpad device when booting/rebooting
|
|
||||||
* their chrome book.
|
|
||||||
*/
|
*/
|
||||||
length = 0;
|
length = 0;
|
||||||
if (gen5_pip->resp_len)
|
if (gen5_pip->resp_len)
|
||||||
|
@ -28,14 +28,13 @@
|
|||||||
#define ETP_PRESSURE_OFFSET 25
|
#define ETP_PRESSURE_OFFSET 25
|
||||||
|
|
||||||
/* IAP Firmware handling */
|
/* IAP Firmware handling */
|
||||||
#define ETP_FW_NAME "elan_i2c.bin"
|
#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
|
||||||
|
#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
|
||||||
#define ETP_IAP_START_ADDR 0x0083
|
#define ETP_IAP_START_ADDR 0x0083
|
||||||
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
|
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
|
||||||
#define ETP_FW_IAP_INTF_ERR (1 << 4)
|
#define ETP_FW_IAP_INTF_ERR (1 << 4)
|
||||||
#define ETP_FW_PAGE_SIZE 64
|
#define ETP_FW_PAGE_SIZE 64
|
||||||
#define ETP_FW_VAILDPAGE_COUNT 768
|
|
||||||
#define ETP_FW_SIGNATURE_SIZE 6
|
#define ETP_FW_SIGNATURE_SIZE 6
|
||||||
#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA
|
|
||||||
|
|
||||||
struct i2c_client;
|
struct i2c_client;
|
||||||
struct completion;
|
struct completion;
|
||||||
@ -58,7 +57,8 @@ struct elan_transport_ops {
|
|||||||
bool max_baseliune, u8 *value);
|
bool max_baseliune, u8 *value);
|
||||||
|
|
||||||
int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
|
int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
|
||||||
int (*get_sm_version)(struct i2c_client *client, u8 *version);
|
int (*get_sm_version)(struct i2c_client *client,
|
||||||
|
u8* ic_type, u8 *version);
|
||||||
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
|
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
|
||||||
int (*get_product_id)(struct i2c_client *client, u8 *id);
|
int (*get_product_id)(struct i2c_client *client, u8 *id);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* Copyright (c) 2013 ELAN Microelectronics Corp.
|
* Copyright (c) 2013 ELAN Microelectronics Corp.
|
||||||
*
|
*
|
||||||
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
|
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
|
||||||
* Version: 1.5.7
|
* Version: 1.5.9
|
||||||
*
|
*
|
||||||
* Based on cyapa driver:
|
* Based on cyapa driver:
|
||||||
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
|
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
|
||||||
@ -40,7 +40,7 @@
|
|||||||
#include "elan_i2c.h"
|
#include "elan_i2c.h"
|
||||||
|
|
||||||
#define DRIVER_NAME "elan_i2c"
|
#define DRIVER_NAME "elan_i2c"
|
||||||
#define ELAN_DRIVER_VERSION "1.5.7"
|
#define ELAN_DRIVER_VERSION "1.5.9"
|
||||||
#define ETP_MAX_PRESSURE 255
|
#define ETP_MAX_PRESSURE 255
|
||||||
#define ETP_FWIDTH_REDUCE 90
|
#define ETP_FWIDTH_REDUCE 90
|
||||||
#define ETP_FINGER_WIDTH 15
|
#define ETP_FINGER_WIDTH 15
|
||||||
@ -83,6 +83,9 @@ struct elan_tp_data {
|
|||||||
u16 fw_checksum;
|
u16 fw_checksum;
|
||||||
int pressure_adjustment;
|
int pressure_adjustment;
|
||||||
u8 mode;
|
u8 mode;
|
||||||
|
u8 ic_type;
|
||||||
|
u16 fw_vaildpage_count;
|
||||||
|
u16 fw_signature_address;
|
||||||
|
|
||||||
bool irq_wake;
|
bool irq_wake;
|
||||||
|
|
||||||
@ -91,6 +94,29 @@ struct elan_tp_data {
|
|||||||
bool baseline_ready;
|
bool baseline_ready;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count,
|
||||||
|
u16 *signature_address)
|
||||||
|
{
|
||||||
|
switch(ic_type) {
|
||||||
|
case 0x09:
|
||||||
|
*vaildpage_count = 768;
|
||||||
|
break;
|
||||||
|
case 0x0D:
|
||||||
|
*vaildpage_count = 896;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* unknown ic type clear value */
|
||||||
|
*vaildpage_count = 0;
|
||||||
|
*signature_address = 0;
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*signature_address =
|
||||||
|
(*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int elan_enable_power(struct elan_tp_data *data)
|
static int elan_enable_power(struct elan_tp_data *data)
|
||||||
{
|
{
|
||||||
int repeat = ETP_RETRY_COUNT;
|
int repeat = ETP_RETRY_COUNT;
|
||||||
@ -221,7 +247,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
error = data->ops->get_sm_version(data->client, &data->sm_version);
|
error = data->ops->get_sm_version(data->client, &data->ic_type,
|
||||||
|
&data->sm_version);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -234,6 +261,14 @@ static int elan_query_device_info(struct elan_tp_data *data)
|
|||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count,
|
||||||
|
&data->fw_signature_address);
|
||||||
|
if (error) {
|
||||||
|
dev_err(&data->client->dev,
|
||||||
|
"unknown ic type %d\n", data->ic_type);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +353,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
|
|||||||
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
|
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
|
||||||
|
|
||||||
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
|
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
|
||||||
for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
|
for (i = boot_page_count; i < data->fw_vaildpage_count; i++) {
|
||||||
u16 checksum = 0;
|
u16 checksum = 0;
|
||||||
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
|
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
|
||||||
|
|
||||||
@ -403,7 +438,8 @@ static ssize_t elan_sysfs_read_product_id(struct device *dev,
|
|||||||
struct i2c_client *client = to_i2c_client(dev);
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
struct elan_tp_data *data = i2c_get_clientdata(client);
|
struct elan_tp_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
return sprintf(buf, "%d.0\n", data->product_id);
|
return sprintf(buf, ETP_PRODUCT_ID_FORMAT_STRING "\n",
|
||||||
|
data->product_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
|
static ssize_t elan_sysfs_read_fw_ver(struct device *dev,
|
||||||
@ -442,19 +478,28 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
|
|||||||
{
|
{
|
||||||
struct elan_tp_data *data = dev_get_drvdata(dev);
|
struct elan_tp_data *data = dev_get_drvdata(dev);
|
||||||
const struct firmware *fw;
|
const struct firmware *fw;
|
||||||
|
char *fw_name;
|
||||||
int error;
|
int error;
|
||||||
const u8 *fw_signature;
|
const u8 *fw_signature;
|
||||||
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
|
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
|
||||||
|
|
||||||
error = request_firmware(&fw, ETP_FW_NAME, dev);
|
/* Look for a firmware with the product id appended. */
|
||||||
|
fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
|
||||||
|
if (!fw_name) {
|
||||||
|
dev_err(dev, "failed to allocate memory for firmware name\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(dev, "requesting fw '%s'\n", fw_name);
|
||||||
|
error = request_firmware(&fw, fw_name, dev);
|
||||||
|
kfree(fw_name);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(dev, "cannot load firmware %s: %d\n",
|
dev_err(dev, "failed to request firmware: %d\n", error);
|
||||||
ETP_FW_NAME, error);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Firmware file must match signature data */
|
/* Firmware file must match signature data */
|
||||||
fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
|
fw_signature = &fw->data[data->fw_signature_address];
|
||||||
if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
|
if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
|
||||||
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
|
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
|
||||||
(int)sizeof(signature), signature,
|
(int)sizeof(signature), signature,
|
||||||
|
@ -259,7 +259,8 @@ static int elan_i2c_get_version(struct i2c_client *client,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
|
static int elan_i2c_get_sm_version(struct i2c_client *client,
|
||||||
|
u8 *ic_type, u8 *version)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
u8 val[3];
|
u8 val[3];
|
||||||
@ -271,6 +272,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, u8 *version)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*version = val[0];
|
*version = val[0];
|
||||||
|
*ic_type = val[1];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +165,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
|
static int elan_smbus_get_sm_version(struct i2c_client *client,
|
||||||
|
u8 *ic_type, u8 *version)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
u8 val[3];
|
u8 val[3];
|
||||||
@ -177,7 +178,8 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *version)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
*version = val[0]; /* XXX Why 0 and not 2 as in IAP/FW versions? */
|
*version = val[0];
|
||||||
|
*ic_type = val[1];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,16 @@ struct focaltech_hw_state {
|
|||||||
*/
|
*/
|
||||||
struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
|
struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finger width 0-7 and 15 for a very big contact area.
|
||||||
|
* 15 value stays until the finger is released.
|
||||||
|
* Width is reported only in absolute packets.
|
||||||
|
* Since hardware reports width only for last touching finger,
|
||||||
|
* there is no need to store width for every specific finger,
|
||||||
|
* so we keep only last value reported.
|
||||||
|
*/
|
||||||
|
unsigned int width;
|
||||||
|
|
||||||
/* True if the clickpad has been pressed. */
|
/* True if the clickpad has been pressed. */
|
||||||
bool pressed;
|
bool pressed;
|
||||||
};
|
};
|
||||||
@ -137,6 +147,7 @@ static void focaltech_report_state(struct psmouse *psmouse)
|
|||||||
input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
|
input_report_abs(dev, ABS_MT_POSITION_X, clamped_x);
|
||||||
input_report_abs(dev, ABS_MT_POSITION_Y,
|
input_report_abs(dev, ABS_MT_POSITION_Y,
|
||||||
priv->y_max - clamped_y);
|
priv->y_max - clamped_y);
|
||||||
|
input_report_abs(dev, ABS_TOOL_WIDTH, state->width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
input_mt_report_pointer_emulation(dev, true);
|
input_mt_report_pointer_emulation(dev, true);
|
||||||
@ -187,6 +198,7 @@ static void focaltech_process_abs_packet(struct psmouse *psmouse,
|
|||||||
|
|
||||||
state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
|
state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
|
||||||
state->fingers[finger].y = (packet[3] << 8) | packet[4];
|
state->fingers[finger].y = (packet[3] << 8) | packet[4];
|
||||||
|
state->width = packet[5] >> 4;
|
||||||
state->fingers[finger].valid = true;
|
state->fingers[finger].valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +343,7 @@ static void focaltech_set_input_params(struct psmouse *psmouse)
|
|||||||
__set_bit(EV_ABS, dev->evbit);
|
__set_bit(EV_ABS, dev->evbit);
|
||||||
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
|
input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
|
||||||
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
|
input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
|
||||||
|
input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);
|
||||||
input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
|
input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
|
||||||
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
|
__set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ static unsigned int psmouse_rate = 100;
|
|||||||
module_param_named(rate, psmouse_rate, uint, 0644);
|
module_param_named(rate, psmouse_rate, uint, 0644);
|
||||||
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
|
MODULE_PARM_DESC(rate, "Report rate, in reports per second.");
|
||||||
|
|
||||||
static bool psmouse_smartscroll = 1;
|
static bool psmouse_smartscroll = true;
|
||||||
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
|
module_param_named(smartscroll, psmouse_smartscroll, bool, 0644);
|
||||||
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
|
MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
|
||||||
|
|
||||||
|
@ -123,11 +123,11 @@ struct fsp_data {
|
|||||||
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
|
extern int fsp_detect(struct psmouse *psmouse, bool set_properties);
|
||||||
extern int fsp_init(struct psmouse *psmouse);
|
extern int fsp_init(struct psmouse *psmouse);
|
||||||
#else
|
#else
|
||||||
inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
|
static inline int fsp_detect(struct psmouse *psmouse, bool set_properties)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
inline int fsp_init(struct psmouse *psmouse)
|
static inline int fsp_init(struct psmouse *psmouse)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@
|
|||||||
#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
|
#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4)
|
||||||
|
|
||||||
/* Control touchpad's No Deceleration option */
|
/* Control touchpad's No Deceleration option */
|
||||||
static bool no_decel = 1;
|
static bool no_decel = true;
|
||||||
module_param(no_decel, bool, 0644);
|
module_param(no_decel, bool, 0644);
|
||||||
MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
|
MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)");
|
||||||
|
|
||||||
@ -340,9 +340,9 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
|
|||||||
s32 data;
|
s32 data;
|
||||||
s8 x_delta, y_delta;
|
s8 x_delta, y_delta;
|
||||||
|
|
||||||
/* Deal with spontanious resets and errors */
|
/* Deal with spontaneous resets and errors */
|
||||||
if (synaptics_i2c_check_error(touch->client))
|
if (synaptics_i2c_check_error(touch->client))
|
||||||
return 0;
|
return false;
|
||||||
|
|
||||||
/* Get Gesture Bit */
|
/* Get Gesture Bit */
|
||||||
data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
|
data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
|
||||||
|
@ -958,6 +958,7 @@ config TOUCHSCREEN_ST1232
|
|||||||
config TOUCHSCREEN_STMPE
|
config TOUCHSCREEN_STMPE
|
||||||
tristate "STMicroelectronics STMPE touchscreens"
|
tristate "STMicroelectronics STMPE touchscreens"
|
||||||
depends on MFD_STMPE
|
depends on MFD_STMPE
|
||||||
|
depends on (OF || COMPILE_TEST)
|
||||||
help
|
help
|
||||||
Say Y here if you want support for STMicroelectronics
|
Say Y here if you want support for STMicroelectronics
|
||||||
STMPE touchscreen controllers.
|
STMPE touchscreen controllers.
|
||||||
|
@ -726,15 +726,15 @@ static void mxt_input_button(struct mxt_data *data, u8 *message)
|
|||||||
{
|
{
|
||||||
struct input_dev *input = data->input_dev;
|
struct input_dev *input = data->input_dev;
|
||||||
const struct mxt_platform_data *pdata = data->pdata;
|
const struct mxt_platform_data *pdata = data->pdata;
|
||||||
bool button;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Active-low switch */
|
|
||||||
for (i = 0; i < pdata->t19_num_keys; i++) {
|
for (i = 0; i < pdata->t19_num_keys; i++) {
|
||||||
if (pdata->t19_keymap[i] == KEY_RESERVED)
|
if (pdata->t19_keymap[i] == KEY_RESERVED)
|
||||||
continue;
|
continue;
|
||||||
button = !(message[1] & (1 << i));
|
|
||||||
input_report_key(input, pdata->t19_keymap[i], button);
|
/* Active-low switch */
|
||||||
|
input_report_key(input, pdata->t19_keymap[i],
|
||||||
|
!(message[1] & BIT(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -775,7 +775,6 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
|
|||||||
struct device *dev = &md->input->dev;
|
struct device *dev = &md->input->dev;
|
||||||
struct cyttsp4_sysinfo *si = md->si;
|
struct cyttsp4_sysinfo *si = md->si;
|
||||||
enum cyttsp4_tch_abs abs;
|
enum cyttsp4_tch_abs abs;
|
||||||
int tmp;
|
|
||||||
bool flipped;
|
bool flipped;
|
||||||
|
|
||||||
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
|
for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
|
||||||
@ -790,9 +789,7 @@ static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (md->pdata->flags & CY_FLAG_FLIP) {
|
if (md->pdata->flags & CY_FLAG_FLIP) {
|
||||||
tmp = touch->abs[CY_TCH_X];
|
swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
|
||||||
touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
|
|
||||||
touch->abs[CY_TCH_Y] = tmp;
|
|
||||||
flipped = true;
|
flipped = true;
|
||||||
} else
|
} else
|
||||||
flipped = false;
|
flipped = false;
|
||||||
|
@ -47,7 +47,7 @@ struct goodix_ts_data {
|
|||||||
/* Register defines */
|
/* Register defines */
|
||||||
#define GOODIX_READ_COOR_ADDR 0x814E
|
#define GOODIX_READ_COOR_ADDR 0x814E
|
||||||
#define GOODIX_REG_CONFIG_DATA 0x8047
|
#define GOODIX_REG_CONFIG_DATA 0x8047
|
||||||
#define GOODIX_REG_VERSION 0x8140
|
#define GOODIX_REG_ID 0x8140
|
||||||
|
|
||||||
#define RESOLUTION_LOC 1
|
#define RESOLUTION_LOC 1
|
||||||
#define MAX_CONTACTS_LOC 5
|
#define MAX_CONTACTS_LOC 5
|
||||||
@ -69,7 +69,7 @@ static const unsigned long goodix_irq_flags[] = {
|
|||||||
* @len: length of the buffer to write
|
* @len: length of the buffer to write
|
||||||
*/
|
*/
|
||||||
static int goodix_i2c_read(struct i2c_client *client,
|
static int goodix_i2c_read(struct i2c_client *client,
|
||||||
u16 reg, u8 *buf, int len)
|
u16 reg, u8 *buf, int len)
|
||||||
{
|
{
|
||||||
struct i2c_msg msgs[2];
|
struct i2c_msg msgs[2];
|
||||||
u16 wbuf = cpu_to_be16(reg);
|
u16 wbuf = cpu_to_be16(reg);
|
||||||
@ -78,7 +78,7 @@ static int goodix_i2c_read(struct i2c_client *client,
|
|||||||
msgs[0].flags = 0;
|
msgs[0].flags = 0;
|
||||||
msgs[0].addr = client->addr;
|
msgs[0].addr = client->addr;
|
||||||
msgs[0].len = 2;
|
msgs[0].len = 2;
|
||||||
msgs[0].buf = (u8 *) &wbuf;
|
msgs[0].buf = (u8 *)&wbuf;
|
||||||
|
|
||||||
msgs[1].flags = I2C_M_RD;
|
msgs[1].flags = I2C_M_RD;
|
||||||
msgs[1].addr = client->addr;
|
msgs[1].addr = client->addr;
|
||||||
@ -101,6 +101,9 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(data[0] & 0x80))
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
touch_num = data[0] & 0x0f;
|
touch_num = data[0] & 0x0f;
|
||||||
if (touch_num > ts->max_touch_num)
|
if (touch_num > ts->max_touch_num)
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
@ -144,7 +147,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
|||||||
*/
|
*/
|
||||||
static void goodix_process_events(struct goodix_ts_data *ts)
|
static void goodix_process_events(struct goodix_ts_data *ts)
|
||||||
{
|
{
|
||||||
u8 point_data[1 + GOODIX_CONTACT_SIZE * ts->max_touch_num];
|
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
|
||||||
int touch_num;
|
int touch_num;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -196,8 +199,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
|
|||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
|
error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
|
||||||
config,
|
config,
|
||||||
GOODIX_CONFIG_MAX_LENGTH);
|
GOODIX_CONFIG_MAX_LENGTH);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_warn(&ts->client->dev,
|
dev_warn(&ts->client->dev,
|
||||||
"Error reading config (%d), using defaults\n",
|
"Error reading config (%d), using defaults\n",
|
||||||
@ -227,22 +230,28 @@ static void goodix_read_config(struct goodix_ts_data *ts)
|
|||||||
*
|
*
|
||||||
* @client: the i2c client
|
* @client: the i2c client
|
||||||
* @version: output buffer containing the version on success
|
* @version: output buffer containing the version on success
|
||||||
|
* @id: output buffer containing the id on success
|
||||||
*/
|
*/
|
||||||
static int goodix_read_version(struct i2c_client *client, u16 *version)
|
static int goodix_read_version(struct i2c_client *client, u16 *version, u16 *id)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
u8 buf[6];
|
u8 buf[6];
|
||||||
|
char id_str[5];
|
||||||
|
|
||||||
error = goodix_i2c_read(client, GOODIX_REG_VERSION, buf, sizeof(buf));
|
error = goodix_i2c_read(client, GOODIX_REG_ID, buf, sizeof(buf));
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&client->dev, "read version failed: %d\n", error);
|
dev_err(&client->dev, "read version failed: %d\n", error);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version)
|
memcpy(id_str, buf, 4);
|
||||||
*version = get_unaligned_le16(&buf[4]);
|
id_str[4] = 0;
|
||||||
|
if (kstrtou16(id_str, 10, id))
|
||||||
|
*id = 0x1001;
|
||||||
|
|
||||||
dev_info(&client->dev, "IC VERSION: %6ph\n", buf);
|
*version = get_unaligned_le16(&buf[4]);
|
||||||
|
|
||||||
|
dev_info(&client->dev, "ID %d, version: %04x\n", *id, *version);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -276,10 +285,13 @@ static int goodix_i2c_test(struct i2c_client *client)
|
|||||||
* goodix_request_input_dev - Allocate, populate and register the input device
|
* goodix_request_input_dev - Allocate, populate and register the input device
|
||||||
*
|
*
|
||||||
* @ts: our goodix_ts_data pointer
|
* @ts: our goodix_ts_data pointer
|
||||||
|
* @version: device firmware version
|
||||||
|
* @id: device ID
|
||||||
*
|
*
|
||||||
* Must be called during probe
|
* Must be called during probe
|
||||||
*/
|
*/
|
||||||
static int goodix_request_input_dev(struct goodix_ts_data *ts)
|
static int goodix_request_input_dev(struct goodix_ts_data *ts, u16 version,
|
||||||
|
u16 id)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -289,14 +301,10 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) |
|
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
|
||||||
BIT_MASK(EV_KEY) |
|
0, ts->abs_x_max, 0, 0);
|
||||||
BIT_MASK(EV_ABS);
|
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
|
||||||
|
0, ts->abs_y_max, 0, 0);
|
||||||
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
|
|
||||||
ts->abs_x_max, 0, 0);
|
|
||||||
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
|
|
||||||
ts->abs_y_max, 0, 0);
|
|
||||||
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
|
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
|
||||||
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
||||||
|
|
||||||
@ -307,8 +315,8 @@ static int goodix_request_input_dev(struct goodix_ts_data *ts)
|
|||||||
ts->input_dev->phys = "input/ts";
|
ts->input_dev->phys = "input/ts";
|
||||||
ts->input_dev->id.bustype = BUS_I2C;
|
ts->input_dev->id.bustype = BUS_I2C;
|
||||||
ts->input_dev->id.vendor = 0x0416;
|
ts->input_dev->id.vendor = 0x0416;
|
||||||
ts->input_dev->id.product = 0x1001;
|
ts->input_dev->id.product = id;
|
||||||
ts->input_dev->id.version = 10427;
|
ts->input_dev->id.version = version;
|
||||||
|
|
||||||
error = input_register_device(ts->input_dev);
|
error = input_register_device(ts->input_dev);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -326,7 +334,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
|||||||
struct goodix_ts_data *ts;
|
struct goodix_ts_data *ts;
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
int error;
|
int error;
|
||||||
u16 version_info;
|
u16 version_info, id_info;
|
||||||
|
|
||||||
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
|
dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr);
|
||||||
|
|
||||||
@ -348,7 +356,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = goodix_read_version(client, &version_info);
|
error = goodix_read_version(client, &version_info, &id_info);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&client->dev, "Read version failed.\n");
|
dev_err(&client->dev, "Read version failed.\n");
|
||||||
return error;
|
return error;
|
||||||
@ -356,7 +364,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
|||||||
|
|
||||||
goodix_read_config(ts);
|
goodix_read_config(ts);
|
||||||
|
|
||||||
error = goodix_request_input_dev(ts);
|
error = goodix_request_input_dev(ts, version_info, id_info);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -411,7 +411,7 @@ static const struct dev_pm_ops s3c_ts_pmops = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_device_id s3cts_driver_ids[] = {
|
static const struct platform_device_id s3cts_driver_ids[] = {
|
||||||
{ "s3c2410-ts", 0 },
|
{ "s3c2410-ts", 0 },
|
||||||
{ "s3c2440-ts", 0 },
|
{ "s3c2440-ts", 0 },
|
||||||
{ "s3c64xx-ts", FEAT_PEN_IRQ },
|
{ "s3c64xx-ts", FEAT_PEN_IRQ },
|
||||||
|
@ -267,27 +267,10 @@ static void stmpe_ts_close(struct input_dev *dev)
|
|||||||
static void stmpe_ts_get_platform_info(struct platform_device *pdev,
|
static void stmpe_ts_get_platform_info(struct platform_device *pdev,
|
||||||
struct stmpe_touch *ts)
|
struct stmpe_touch *ts)
|
||||||
{
|
{
|
||||||
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
|
|
||||||
struct device_node *np = pdev->dev.of_node;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct stmpe_ts_platform_data *ts_pdata = NULL;
|
u32 val;
|
||||||
|
|
||||||
ts->stmpe = stmpe;
|
|
||||||
|
|
||||||
if (stmpe->pdata && stmpe->pdata->ts) {
|
|
||||||
ts_pdata = stmpe->pdata->ts;
|
|
||||||
|
|
||||||
ts->sample_time = ts_pdata->sample_time;
|
|
||||||
ts->mod_12b = ts_pdata->mod_12b;
|
|
||||||
ts->ref_sel = ts_pdata->ref_sel;
|
|
||||||
ts->adc_freq = ts_pdata->adc_freq;
|
|
||||||
ts->ave_ctrl = ts_pdata->ave_ctrl;
|
|
||||||
ts->touch_det_delay = ts_pdata->touch_det_delay;
|
|
||||||
ts->settling = ts_pdata->settling;
|
|
||||||
ts->fraction_z = ts_pdata->fraction_z;
|
|
||||||
ts->i_drive = ts_pdata->i_drive;
|
|
||||||
} else if (np) {
|
|
||||||
u32 val;
|
|
||||||
|
|
||||||
|
if (np) {
|
||||||
if (!of_property_read_u32(np, "st,sample-time", &val))
|
if (!of_property_read_u32(np, "st,sample-time", &val))
|
||||||
ts->sample_time = val;
|
ts->sample_time = val;
|
||||||
if (!of_property_read_u32(np, "st,mod-12b", &val))
|
if (!of_property_read_u32(np, "st,mod-12b", &val))
|
||||||
@ -311,6 +294,7 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev,
|
|||||||
|
|
||||||
static int stmpe_input_probe(struct platform_device *pdev)
|
static int stmpe_input_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct stmpe_touch *ts;
|
struct stmpe_touch *ts;
|
||||||
struct input_dev *idev;
|
struct input_dev *idev;
|
||||||
int error;
|
int error;
|
||||||
@ -329,6 +313,7 @@ static int stmpe_input_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ts);
|
platform_set_drvdata(pdev, ts);
|
||||||
|
ts->stmpe = stmpe;
|
||||||
ts->idev = idev;
|
ts->idev = idev;
|
||||||
ts->dev = &pdev->dev;
|
ts->dev = &pdev->dev;
|
||||||
|
|
||||||
@ -351,14 +336,13 @@ static int stmpe_input_probe(struct platform_device *pdev)
|
|||||||
idev->name = STMPE_TS_NAME;
|
idev->name = STMPE_TS_NAME;
|
||||||
idev->phys = STMPE_TS_NAME"/input0";
|
idev->phys = STMPE_TS_NAME"/input0";
|
||||||
idev->id.bustype = BUS_I2C;
|
idev->id.bustype = BUS_I2C;
|
||||||
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
|
||||||
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
|
||||||
|
|
||||||
idev->open = stmpe_ts_open;
|
idev->open = stmpe_ts_open;
|
||||||
idev->close = stmpe_ts_close;
|
idev->close = stmpe_ts_close;
|
||||||
|
|
||||||
input_set_drvdata(idev, ts);
|
input_set_drvdata(idev, ts);
|
||||||
|
|
||||||
|
input_set_capability(idev, EV_KEY, BTN_TOUCH);
|
||||||
input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
|
input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
|
||||||
input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
|
input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
|
||||||
input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
|
input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
|
||||||
@ -383,14 +367,19 @@ static int stmpe_ts_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
static struct platform_driver stmpe_ts_driver = {
|
static struct platform_driver stmpe_ts_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = STMPE_TS_NAME,
|
.name = STMPE_TS_NAME,
|
||||||
},
|
},
|
||||||
.probe = stmpe_input_probe,
|
.probe = stmpe_input_probe,
|
||||||
.remove = stmpe_ts_remove,
|
.remove = stmpe_ts_remove,
|
||||||
};
|
};
|
||||||
module_platform_driver(stmpe_ts_driver);
|
module_platform_driver(stmpe_ts_driver);
|
||||||
|
|
||||||
|
static const struct of_device_id stmpe_ts_ids[] = {
|
||||||
|
{ .compatible = "st,stmpe-ts", },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
|
||||||
|
|
||||||
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
|
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
|
||||||
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
|
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_ALIAS("platform:" STMPE_TS_NAME);
|
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
#include <linux/input/mt.h>
|
#include <linux/input/mt.h>
|
||||||
#include <linux/platform_data/zforce_ts.h>
|
#include <linux/platform_data/zforce_ts.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_gpio.h>
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
|
@ -11,9 +11,6 @@ menuconfig NEW_LEDS
|
|||||||
Say Y to enable Linux LED support. This allows control of supported
|
Say Y to enable Linux LED support. This allows control of supported
|
||||||
LEDs from both userspace and optionally, by kernel events (triggers).
|
LEDs from both userspace and optionally, by kernel events (triggers).
|
||||||
|
|
||||||
This is not related to standard keyboard LEDs which are controlled
|
|
||||||
via the input system.
|
|
||||||
|
|
||||||
if NEW_LEDS
|
if NEW_LEDS
|
||||||
|
|
||||||
config LEDS_CLASS
|
config LEDS_CLASS
|
||||||
|
@ -55,9 +55,6 @@
|
|||||||
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
|
static int __read_mostly sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
|
||||||
static bool __read_mostly sysrq_always_enabled;
|
static bool __read_mostly sysrq_always_enabled;
|
||||||
|
|
||||||
unsigned short platform_sysrq_reset_seq[] __weak = { KEY_RESERVED };
|
|
||||||
int sysrq_reset_downtime_ms __weak;
|
|
||||||
|
|
||||||
static bool sysrq_on(void)
|
static bool sysrq_on(void)
|
||||||
{
|
{
|
||||||
return sysrq_enabled || sysrq_always_enabled;
|
return sysrq_enabled || sysrq_always_enabled;
|
||||||
@ -568,6 +565,7 @@ void handle_sysrq(int key)
|
|||||||
EXPORT_SYMBOL(handle_sysrq);
|
EXPORT_SYMBOL(handle_sysrq);
|
||||||
|
|
||||||
#ifdef CONFIG_INPUT
|
#ifdef CONFIG_INPUT
|
||||||
|
static int sysrq_reset_downtime_ms;
|
||||||
|
|
||||||
/* Simple translation table for the SysRq keys */
|
/* Simple translation table for the SysRq keys */
|
||||||
static const unsigned char sysrq_xlate[KEY_CNT] =
|
static const unsigned char sysrq_xlate[KEY_CNT] =
|
||||||
@ -948,23 +946,8 @@ static bool sysrq_handler_registered;
|
|||||||
|
|
||||||
static inline void sysrq_register_handler(void)
|
static inline void sysrq_register_handler(void)
|
||||||
{
|
{
|
||||||
unsigned short key;
|
|
||||||
int error;
|
int error;
|
||||||
int i;
|
|
||||||
|
|
||||||
/* First check if a __weak interface was instantiated. */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
|
|
||||||
key = platform_sysrq_reset_seq[i];
|
|
||||||
if (key == KEY_RESERVED || key > KEY_MAX)
|
|
||||||
break;
|
|
||||||
|
|
||||||
sysrq_reset_seq[sysrq_reset_seq_len++] = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DT configuration takes precedence over anything that would
|
|
||||||
* have been defined via the __weak interface.
|
|
||||||
*/
|
|
||||||
sysrq_of_get_keyreset_config();
|
sysrq_of_get_keyreset_config();
|
||||||
|
|
||||||
error = input_register_handler(&sysrq_handler);
|
error = input_register_handler(&sysrq_handler);
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
#include <linux/kbd_kern.h>
|
#include <linux/kbd_kern.h>
|
||||||
#include <linux/kbd_diacr.h>
|
#include <linux/kbd_diacr.h>
|
||||||
@ -129,7 +130,7 @@ static char rep; /* flag telling character repeat */
|
|||||||
|
|
||||||
static int shift_state = 0;
|
static int shift_state = 0;
|
||||||
|
|
||||||
static unsigned char ledstate = 0xff; /* undefined */
|
static unsigned int ledstate = -1U; /* undefined */
|
||||||
static unsigned char ledioctl;
|
static unsigned char ledioctl;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -961,6 +962,122 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS)
|
||||||
|
|
||||||
|
struct kbd_led_trigger {
|
||||||
|
struct led_trigger trigger;
|
||||||
|
unsigned int mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void kbd_led_trigger_activate(struct led_classdev *cdev)
|
||||||
|
{
|
||||||
|
struct kbd_led_trigger *trigger =
|
||||||
|
container_of(cdev->trigger, struct kbd_led_trigger, trigger);
|
||||||
|
|
||||||
|
tasklet_disable(&keyboard_tasklet);
|
||||||
|
if (ledstate != -1U)
|
||||||
|
led_trigger_event(&trigger->trigger,
|
||||||
|
ledstate & trigger->mask ?
|
||||||
|
LED_FULL : LED_OFF);
|
||||||
|
tasklet_enable(&keyboard_tasklet);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KBD_LED_TRIGGER(_led_bit, _name) { \
|
||||||
|
.trigger = { \
|
||||||
|
.name = _name, \
|
||||||
|
.activate = kbd_led_trigger_activate, \
|
||||||
|
}, \
|
||||||
|
.mask = BIT(_led_bit), \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \
|
||||||
|
KBD_LED_TRIGGER((_led_bit) + 8, _name)
|
||||||
|
|
||||||
|
static struct kbd_led_trigger kbd_led_triggers[] = {
|
||||||
|
KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"),
|
||||||
|
KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"),
|
||||||
|
KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"),
|
||||||
|
KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"),
|
||||||
|
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"),
|
||||||
|
KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void kbd_propagate_led_state(unsigned int old_state,
|
||||||
|
unsigned int new_state)
|
||||||
|
{
|
||||||
|
struct kbd_led_trigger *trigger;
|
||||||
|
unsigned int changed = old_state ^ new_state;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
|
||||||
|
trigger = &kbd_led_triggers[i];
|
||||||
|
|
||||||
|
if (changed & trigger->mask)
|
||||||
|
led_trigger_event(&trigger->trigger,
|
||||||
|
new_state & trigger->mask ?
|
||||||
|
LED_FULL : LED_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
|
||||||
|
{
|
||||||
|
unsigned int led_state = *(unsigned int *)data;
|
||||||
|
|
||||||
|
if (test_bit(EV_LED, handle->dev->evbit))
|
||||||
|
kbd_propagate_led_state(~led_state, led_state);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kbd_init_leds(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) {
|
||||||
|
error = led_trigger_register(&kbd_led_triggers[i].trigger);
|
||||||
|
if (error)
|
||||||
|
pr_err("error %d while registering trigger %s\n",
|
||||||
|
error, kbd_led_triggers[i].trigger.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
|
||||||
|
{
|
||||||
|
unsigned int leds = *(unsigned int *)data;
|
||||||
|
|
||||||
|
if (test_bit(EV_LED, handle->dev->evbit)) {
|
||||||
|
input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
|
||||||
|
input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
|
||||||
|
input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
|
||||||
|
input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kbd_propagate_led_state(unsigned int old_state,
|
||||||
|
unsigned int new_state)
|
||||||
|
{
|
||||||
|
input_handler_for_each_handle(&kbd_handler, &new_state,
|
||||||
|
kbd_update_leds_helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void kbd_init_leds(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
|
* The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
|
||||||
* or (ii) whatever pattern of lights people want to show using KDSETLED,
|
* or (ii) whatever pattern of lights people want to show using KDSETLED,
|
||||||
@ -968,7 +1085,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
|
|||||||
*/
|
*/
|
||||||
static unsigned char getledstate(void)
|
static unsigned char getledstate(void)
|
||||||
{
|
{
|
||||||
return ledstate;
|
return ledstate & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setledstate(struct kbd_struct *kb, unsigned int led)
|
void setledstate(struct kbd_struct *kb, unsigned int led)
|
||||||
@ -995,20 +1112,6 @@ static inline unsigned char getleds(void)
|
|||||||
return kb->ledflagstate;
|
return kb->ledflagstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kbd_update_leds_helper(struct input_handle *handle, void *data)
|
|
||||||
{
|
|
||||||
unsigned char leds = *(unsigned char *)data;
|
|
||||||
|
|
||||||
if (test_bit(EV_LED, handle->dev->evbit)) {
|
|
||||||
input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
|
|
||||||
input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
|
|
||||||
input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
|
|
||||||
input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vt_get_leds - helper for braille console
|
* vt_get_leds - helper for braille console
|
||||||
* @console: console to read
|
* @console: console to read
|
||||||
@ -1085,24 +1188,23 @@ void vt_kbd_con_stop(int console)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the tasklet that updates LED state on all keyboards
|
* This is the tasklet that updates LED state of LEDs using standard
|
||||||
* attached to the box. The reason we use tasklet is that we
|
* keyboard triggers. The reason we use tasklet is that we need to
|
||||||
* need to handle the scenario when keyboard handler is not
|
* handle the scenario when keyboard handler is not registered yet
|
||||||
* registered yet but we already getting updates from the VT to
|
* but we already getting updates from the VT to update led state.
|
||||||
* update led state.
|
|
||||||
*/
|
*/
|
||||||
static void kbd_bh(unsigned long dummy)
|
static void kbd_bh(unsigned long dummy)
|
||||||
{
|
{
|
||||||
unsigned char leds;
|
unsigned int leds;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&led_lock, flags);
|
spin_lock_irqsave(&led_lock, flags);
|
||||||
leds = getleds();
|
leds = getleds();
|
||||||
|
leds |= (unsigned int)kbd->lockstate << 8;
|
||||||
spin_unlock_irqrestore(&led_lock, flags);
|
spin_unlock_irqrestore(&led_lock, flags);
|
||||||
|
|
||||||
if (leds != ledstate) {
|
if (leds != ledstate) {
|
||||||
input_handler_for_each_handle(&kbd_handler, &leds,
|
kbd_propagate_led_state(ledstate, leds);
|
||||||
kbd_update_leds_helper);
|
|
||||||
ledstate = leds;
|
ledstate = leds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1450,7 +1552,7 @@ static void kbd_start(struct input_handle *handle)
|
|||||||
{
|
{
|
||||||
tasklet_disable(&keyboard_tasklet);
|
tasklet_disable(&keyboard_tasklet);
|
||||||
|
|
||||||
if (ledstate != 0xff)
|
if (ledstate != -1U)
|
||||||
kbd_update_leds_helper(handle, &ledstate);
|
kbd_update_leds_helper(handle, &ledstate);
|
||||||
|
|
||||||
tasklet_enable(&keyboard_tasklet);
|
tasklet_enable(&keyboard_tasklet);
|
||||||
@ -1497,6 +1599,8 @@ int __init kbd_init(void)
|
|||||||
kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
|
kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kbd_init_leds();
|
||||||
|
|
||||||
error = input_register_handler(&kbd_handler);
|
error = input_register_handler(&kbd_handler);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -103,6 +103,7 @@ struct da9063;
|
|||||||
struct da9063_pdata {
|
struct da9063_pdata {
|
||||||
int (*init)(struct da9063 *da9063);
|
int (*init)(struct da9063 *da9063);
|
||||||
int irq_base;
|
int irq_base;
|
||||||
|
bool key_power;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
struct da9063_regulators_pdata *regulators_pdata;
|
struct da9063_regulators_pdata *regulators_pdata;
|
||||||
struct led_platform_data *leds_pdata;
|
struct led_platform_data *leds_pdata;
|
||||||
|
@ -117,47 +117,6 @@ extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
|
|||||||
|
|
||||||
#define STMPE_GPIO_NOREQ_811_TOUCH (0xf0)
|
#define STMPE_GPIO_NOREQ_811_TOUCH (0xf0)
|
||||||
|
|
||||||
/**
|
|
||||||
* struct stmpe_ts_platform_data - stmpe811 touch screen controller platform
|
|
||||||
* data
|
|
||||||
* @sample_time: ADC converstion time in number of clock.
|
|
||||||
* (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
|
|
||||||
* 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
|
|
||||||
* recommended is 4.
|
|
||||||
* @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
|
|
||||||
* @ref_sel: ADC reference source
|
|
||||||
* (0 -> internal reference, 1 -> external reference)
|
|
||||||
* @adc_freq: ADC Clock speed
|
|
||||||
* (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
|
|
||||||
* @ave_ctrl: Sample average control
|
|
||||||
* (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
|
|
||||||
* @touch_det_delay: Touch detect interrupt delay
|
|
||||||
* (0 -> 10 us, 1 -> 50 us, 2 -> 100 us, 3 -> 500 us,
|
|
||||||
* 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms)
|
|
||||||
* recommended is 3
|
|
||||||
* @settling: Panel driver settling time
|
|
||||||
* (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 -> 1 ms,
|
|
||||||
* 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms)
|
|
||||||
* recommended is 2
|
|
||||||
* @fraction_z: Length of the fractional part in z
|
|
||||||
* (fraction_z ([0..7]) = Count of the fractional part)
|
|
||||||
* recommended is 7
|
|
||||||
* @i_drive: current limit value of the touchscreen drivers
|
|
||||||
* (0 -> 20 mA typical 35 mA max, 1 -> 50 mA typical 80 mA max)
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
struct stmpe_ts_platform_data {
|
|
||||||
u8 sample_time;
|
|
||||||
u8 mod_12b;
|
|
||||||
u8 ref_sel;
|
|
||||||
u8 adc_freq;
|
|
||||||
u8 ave_ctrl;
|
|
||||||
u8 touch_det_delay;
|
|
||||||
u8 settling;
|
|
||||||
u8 fraction_z;
|
|
||||||
u8 i_drive;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct stmpe_platform_data - STMPE platform data
|
* struct stmpe_platform_data - STMPE platform data
|
||||||
* @id: device id to distinguish between multiple STMPEs on the same board
|
* @id: device id to distinguish between multiple STMPEs on the same board
|
||||||
@ -168,7 +127,6 @@ struct stmpe_ts_platform_data {
|
|||||||
* @irq_over_gpio: true if gpio is used to get irq
|
* @irq_over_gpio: true if gpio is used to get irq
|
||||||
* @irq_gpio: gpio number over which irq will be requested (significant only if
|
* @irq_gpio: gpio number over which irq will be requested (significant only if
|
||||||
* irq_over_gpio is true)
|
* irq_over_gpio is true)
|
||||||
* @ts: touchscreen-specific platform data
|
|
||||||
*/
|
*/
|
||||||
struct stmpe_platform_data {
|
struct stmpe_platform_data {
|
||||||
int id;
|
int id;
|
||||||
@ -178,8 +136,6 @@ struct stmpe_platform_data {
|
|||||||
bool irq_over_gpio;
|
bool irq_over_gpio;
|
||||||
int irq_gpio;
|
int irq_gpio;
|
||||||
int autosleep_timeout;
|
int autosleep_timeout;
|
||||||
|
|
||||||
struct stmpe_ts_platform_data *ts;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010 ST Microelectronics
|
* Copyright (C) 2010 ST Microelectronics
|
||||||
* Rajeev Kumar<rajeev-dlh.kumar@st.com>
|
* Rajeev Kumar <rajeevkumar.linux@gmail.com>
|
||||||
*
|
*
|
||||||
* This file is licensed under the terms of the GNU General Public
|
* This file is licensed under the terms of the GNU General Public
|
||||||
* License version 2. This program is licensed "as is" without any
|
* License version 2. This program is licensed "as is" without any
|
||||||
|
Loading…
Reference in New Issue
Block a user