Merge branch 'next' into for-linus

Prepare first round of input updates for 4.2 merge window.
This commit is contained in:
Dmitry Torokhov 2015-06-22 09:26:29 -07:00
commit f7ebc4dcde
53 changed files with 1277 additions and 374 deletions

View File

@ -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)

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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
View 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");

View File

@ -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.
*/ */

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View 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);

View File

@ -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) {

View 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>");

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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.");

View File

@ -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;
} }

View File

@ -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);

View File

@ -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.

View File

@ -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)));
} }
} }

View File

@ -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;

View File

@ -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;

View File

@ -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 },

View File

@ -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);

View File

@ -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>

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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