Merge tag 'v4.3-rc3' into next
Merge with Linux 4.3-rc3 to bring in MFD DA9062 changes to merge DA9062 OnKey driver.
This commit is contained in:
@@ -149,9 +149,9 @@ static int old_gameport_measure_speed(struct gameport *gameport)
|
||||
|
||||
for(i = 0; i < 50; i++) {
|
||||
local_irq_save(flags);
|
||||
rdtscl(t1);
|
||||
t1 = rdtsc();
|
||||
for (t = 0; t < 50; t++) gameport_read(gameport);
|
||||
rdtscl(t2);
|
||||
t2 = rdtsc();
|
||||
local_irq_restore(flags);
|
||||
udelay(i * 10);
|
||||
if (t2 - t1 < tx) tx = t2 - t1;
|
||||
|
@@ -71,6 +71,18 @@ static void input_leds_event(struct input_handle *handle, unsigned int type,
|
||||
{
|
||||
}
|
||||
|
||||
static int input_leds_get_count(struct input_dev *dev)
|
||||
{
|
||||
unsigned int led_code;
|
||||
int count = 0;
|
||||
|
||||
for_each_set_bit(led_code, dev->ledbit, LED_CNT)
|
||||
if (input_led_info[led_code].name)
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int input_leds_connect(struct input_handler *handler,
|
||||
struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
@@ -81,7 +93,7 @@ static int input_leds_connect(struct input_handler *handler,
|
||||
int led_no;
|
||||
int error;
|
||||
|
||||
num_leds = bitmap_weight(dev->ledbit, LED_CNT);
|
||||
num_leds = input_leds_get_count(dev);
|
||||
if (!num_leds)
|
||||
return -ENXIO;
|
||||
|
||||
@@ -112,7 +124,7 @@ static int input_leds_connect(struct input_handler *handler,
|
||||
led->handle = &leds->handle;
|
||||
led->code = led_code;
|
||||
|
||||
if (WARN_ON(!input_led_info[led_code].name))
|
||||
if (!input_led_info[led_code].name)
|
||||
continue;
|
||||
|
||||
led->cdev.name = kasprintf(GFP_KERNEL, "%s::%s",
|
||||
|
@@ -143,7 +143,7 @@ struct analog_port {
|
||||
|
||||
#include <linux/i8253.h>
|
||||
|
||||
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
|
||||
#define GET_TIME(x) do { if (cpu_has_tsc) x = (unsigned int)rdtsc(); else x = get_time_pit(); } while (0)
|
||||
#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
|
||||
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
|
||||
static unsigned int get_time_pit(void)
|
||||
@@ -160,7 +160,7 @@ static unsigned int get_time_pit(void)
|
||||
return count;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
#define GET_TIME(x) rdtscl(x)
|
||||
#define GET_TIME(x) do { x = (unsigned int)rdtsc(); } while (0)
|
||||
#define DELTA(x,y) ((y)-(x))
|
||||
#define TIME_NAME "TSC"
|
||||
#elif defined(__alpha__) || defined(CONFIG_MN10300) || defined(CONFIG_ARM) || defined(CONFIG_ARM64) || defined(CONFIG_TILE)
|
||||
|
@@ -205,7 +205,7 @@ static void tgfx_attach(struct parport *pp)
|
||||
if (n_buttons[i] < 1)
|
||||
continue;
|
||||
|
||||
if (n_buttons[i] > 6) {
|
||||
if (n_buttons[i] > ARRAY_SIZE(tgfx_buttons)) {
|
||||
printk(KERN_ERR "turbografx.c: Invalid number of buttons %d\n", n_buttons[i]);
|
||||
goto err_unreg_devs;
|
||||
}
|
||||
|
@@ -401,6 +401,17 @@ config KEYBOARD_MPR121
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called mpr121_touchkey.
|
||||
|
||||
config KEYBOARD_SNVS_PWRKEY
|
||||
tristate "IMX SNVS Power Key Driver"
|
||||
depends on SOC_IMX6SX
|
||||
depends on OF
|
||||
help
|
||||
This is the snvs powerkey driver for the Freescale i.MX application
|
||||
processors that are newer than i.MX6 SX.
|
||||
|
||||
To compile this driver as a module, choose M here; the
|
||||
module will be called snvs_pwrkey.
|
||||
|
||||
config KEYBOARD_IMX
|
||||
tristate "IMX keypad support"
|
||||
depends on ARCH_MXC
|
||||
|
@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
|
||||
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
|
||||
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
|
||||
obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o
|
||||
obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
|
||||
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
|
||||
|
@@ -249,7 +249,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
|
||||
* convert it to descriptor.
|
||||
*/
|
||||
if (!button->gpiod && gpio_is_valid(button->gpio)) {
|
||||
unsigned flags = 0;
|
||||
unsigned flags = GPIOF_IN;
|
||||
|
||||
if (button->active_low)
|
||||
flags |= GPIOF_ACTIVE_LOW;
|
||||
|
227
drivers/input/keyboard/snvs_pwrkey.c
Normal file
227
drivers/input/keyboard/snvs_pwrkey.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Driver for the IMX SNVS ON/OFF Power Key
|
||||
* Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define SNVS_LPSR_REG 0x4C /* LP Status Register */
|
||||
#define SNVS_LPCR_REG 0x38 /* LP Control Register */
|
||||
#define SNVS_HPSR_REG 0x14
|
||||
#define SNVS_HPSR_BTN BIT(6)
|
||||
#define SNVS_LPSR_SPO BIT(18)
|
||||
#define SNVS_LPCR_DEP_EN BIT(5)
|
||||
|
||||
#define DEBOUNCE_TIME 30
|
||||
#define REPEAT_INTERVAL 60
|
||||
|
||||
struct pwrkey_drv_data {
|
||||
struct regmap *snvs;
|
||||
int irq;
|
||||
int keycode;
|
||||
int keystate; /* 1:pressed */
|
||||
int wakeup;
|
||||
struct timer_list check_timer;
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
static void imx_imx_snvs_check_for_events(unsigned long data)
|
||||
{
|
||||
struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
|
||||
struct input_dev *input = pdata->input;
|
||||
u32 state;
|
||||
|
||||
regmap_read(pdata->snvs, SNVS_HPSR_REG, &state);
|
||||
state = state & SNVS_HPSR_BTN ? 1 : 0;
|
||||
|
||||
/* only report new event if status changed */
|
||||
if (state ^ pdata->keystate) {
|
||||
pdata->keystate = state;
|
||||
input_event(input, EV_KEY, pdata->keycode, state);
|
||||
input_sync(input);
|
||||
pm_relax(pdata->input->dev.parent);
|
||||
}
|
||||
|
||||
/* repeat check if pressed long */
|
||||
if (state) {
|
||||
mod_timer(&pdata->check_timer,
|
||||
jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
u32 lp_status;
|
||||
|
||||
pm_wakeup_event(pdata->input->dev.parent, 0);
|
||||
|
||||
regmap_read(pdata->snvs, SNVS_LPSR_REG, &lp_status);
|
||||
if (lp_status & SNVS_LPSR_SPO)
|
||||
mod_timer(&pdata->check_timer, jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
|
||||
|
||||
/* clear SPO status */
|
||||
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void imx_snvs_pwrkey_act(void *pdata)
|
||||
{
|
||||
struct pwrkey_drv_data *pd = pdata;
|
||||
|
||||
del_timer_sync(&pd->check_timer);
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pwrkey_drv_data *pdata = NULL;
|
||||
struct input_dev *input = NULL;
|
||||
struct device_node *np;
|
||||
int error;
|
||||
|
||||
/* Get SNVS register Page */
|
||||
np = pdev->dev.of_node;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata->snvs = syscon_regmap_lookup_by_phandle(np, "regmap");;
|
||||
|
||||
if (!pdata->snvs) {
|
||||
dev_err(&pdev->dev, "Can't get snvs syscon\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(np, "linux,keycode", &pdata->keycode)) {
|
||||
pdata->keycode = KEY_POWER;
|
||||
dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
|
||||
}
|
||||
|
||||
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
|
||||
|
||||
pdata->irq = platform_get_irq(pdev, 0);
|
||||
if (pdata->irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq defined in platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_DEP_EN, SNVS_LPCR_DEP_EN);
|
||||
|
||||
/* clear the unexpected interrupt before driver ready */
|
||||
regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
|
||||
|
||||
setup_timer(&pdata->check_timer,
|
||||
imx_imx_snvs_check_for_events, (unsigned long) pdata);
|
||||
|
||||
input = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input) {
|
||||
dev_err(&pdev->dev, "failed to allocate the input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = "snvs-pwrkey/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
|
||||
input_set_capability(input, EV_KEY, pdata->keycode);
|
||||
|
||||
/* input customer action to cancel release timer */
|
||||
error = devm_add_action(&pdev->dev, imx_snvs_pwrkey_act, pdata);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register remove action\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = devm_request_irq(&pdev->dev, pdata->irq,
|
||||
imx_snvs_pwrkey_interrupt,
|
||||
0, pdev->name, pdev);
|
||||
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "interrupt not available.\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error < 0) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
input_free_device(input);
|
||||
return error;
|
||||
}
|
||||
|
||||
pdata->input = input;
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(pdata->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_snvs_pwrkey_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pwrkey_drv_data *pdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
disable_irq_wake(pdata->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id imx_snvs_pwrkey_ids[] = {
|
||||
{ .compatible = "fsl,sec-v4.0-pwrkey" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx_snvs_pwrkey_ids);
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(imx_snvs_pwrkey_pm_ops, imx_snvs_pwrkey_suspend,
|
||||
imx_snvs_pwrkey_resume);
|
||||
|
||||
static struct platform_driver imx_snvs_pwrkey_driver = {
|
||||
.driver = {
|
||||
.name = "snvs_pwrkey",
|
||||
.pm = &imx_snvs_pwrkey_pm_ops,
|
||||
.of_match_table = imx_snvs_pwrkey_ids,
|
||||
},
|
||||
.probe = imx_snvs_pwrkey_probe,
|
||||
};
|
||||
module_platform_driver(imx_snvs_pwrkey_driver);
|
||||
|
||||
MODULE_AUTHOR("Freescale Semiconductor");
|
||||
MODULE_DESCRIPTION("i.MX snvs power key Driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -167,28 +167,16 @@ config INPUT_M68K_BEEP
|
||||
depends on M68K
|
||||
|
||||
config INPUT_MAX77693_HAPTIC
|
||||
tristate "MAXIM MAX77693 haptic controller support"
|
||||
depends on MFD_MAX77693 && PWM
|
||||
tristate "MAXIM MAX77693/MAX77843 haptic controller support"
|
||||
depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
This option enables support for the haptic controller on
|
||||
MAXIM MAX77693 chip.
|
||||
MAXIM MAX77693 and MAX77843 chips.
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called max77693-haptic.
|
||||
|
||||
config INPUT_MAX77843_HAPTIC
|
||||
tristate "MAXIM MAX77843 haptic controller support"
|
||||
depends on MFD_MAX77843 && REGULATOR
|
||||
select INPUT_FF_MEMLESS
|
||||
help
|
||||
This option enables support for the haptic controller on
|
||||
MAXIM MAX77843 chip. The driver supports ff-memless interface
|
||||
from input framework.
|
||||
|
||||
To compile this driver as module, choose M here: the
|
||||
module will be called max77843-haptic.
|
||||
|
||||
config INPUT_MAX8925_ONKEY
|
||||
tristate "MAX8925 ONKEY support"
|
||||
depends on MFD_MAX8925
|
||||
|
@@ -41,7 +41,6 @@ obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
||||
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
|
||||
obj-$(CONFIG_INPUT_MAX77843_HAPTIC) += max77843-haptic.o
|
||||
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
||||
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
||||
|
@@ -292,3 +292,4 @@ module_platform_driver(axp20x_pek_driver);
|
||||
MODULE_DESCRIPTION("axp20x Power Button");
|
||||
MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:axp20x-pek");
|
||||
|
@@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input)
|
||||
gpiod_set_value(haptics->enable_gpio, 0);
|
||||
}
|
||||
|
||||
static const struct reg_default drv260x_lra_cal_regs[] = {
|
||||
static const struct reg_sequence drv260x_lra_cal_regs[] = {
|
||||
{ DRV260X_MODE, DRV260X_AUTO_CAL },
|
||||
{ DRV260X_CTRL3, DRV260X_NG_THRESH_2 },
|
||||
{ DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |
|
||||
DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
|
||||
};
|
||||
|
||||
static const struct reg_default drv260x_lra_init_regs[] = {
|
||||
static const struct reg_sequence drv260x_lra_init_regs[] = {
|
||||
{ DRV260X_MODE, DRV260X_RT_PLAYBACK },
|
||||
{ DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS |
|
||||
DRV260X_AUDIO_HAPTICS_FILTER_125HZ },
|
||||
@@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = {
|
||||
{ DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
|
||||
};
|
||||
|
||||
static const struct reg_default drv260x_erm_cal_regs[] = {
|
||||
static const struct reg_sequence drv260x_erm_cal_regs[] = {
|
||||
{ DRV260X_MODE, DRV260X_AUTO_CAL },
|
||||
{ DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT },
|
||||
{ DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT },
|
||||
|
@@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input)
|
||||
"Failed to enter standby mode: %d\n", error);
|
||||
}
|
||||
|
||||
static const struct reg_default drv2665_init_regs[] = {
|
||||
static const struct reg_sequence drv2665_init_regs[] = {
|
||||
{ DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
|
||||
{ DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
|
||||
};
|
||||
|
@@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input)
|
||||
"Failed to enter standby mode: %d\n", error);
|
||||
}
|
||||
|
||||
static const struct reg_default drv2667_init_regs[] = {
|
||||
static const struct reg_sequence drv2667_init_regs[] = {
|
||||
{ DRV2667_CTRL_2, 0 },
|
||||
{ DRV2667_CTRL_1, DRV2667_25_VPP_GAIN },
|
||||
{ DRV2667_WV_SEQ_0, 1 },
|
||||
{ DRV2667_WV_SEQ_1, 0 }
|
||||
};
|
||||
|
||||
static const struct reg_default drv2667_page1_init[] = {
|
||||
static const struct reg_sequence drv2667_page1_init[] = {
|
||||
{ DRV2667_RAM_HDR_SZ, 0x05 },
|
||||
{ DRV2667_RAM_START_HI, 0x80 },
|
||||
{ DRV2667_RAM_START_LO, 0x06 },
|
||||
|
@@ -1,8 +1,9 @@
|
||||
/*
|
||||
* MAXIM MAX77693 Haptic device driver
|
||||
* MAXIM MAX77693/MAX77843 Haptic device driver
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electronics
|
||||
* Copyright (C) 2014,2015 Samsung Electronics
|
||||
* Jaewon Kim <jaewon02.kim@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
* This program is not provided / owned by Maxim Integrated Products.
|
||||
*
|
||||
@@ -24,7 +25,9 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/mfd/max77693.h>
|
||||
#include <linux/mfd/max77693-common.h>
|
||||
#include <linux/mfd/max77693-private.h>
|
||||
#include <linux/mfd/max77843-private.h>
|
||||
|
||||
#define MAX_MAGNITUDE_SHIFT 16
|
||||
|
||||
@@ -46,6 +49,8 @@ enum max77693_haptic_pwm_divisor {
|
||||
};
|
||||
|
||||
struct max77693_haptic {
|
||||
enum max77693_types dev_type;
|
||||
|
||||
struct regmap *regmap_pmic;
|
||||
struct regmap *regmap_haptic;
|
||||
struct device *dev;
|
||||
@@ -59,7 +64,6 @@ struct max77693_haptic {
|
||||
unsigned int pwm_duty;
|
||||
enum max77693_haptic_motor_type type;
|
||||
enum max77693_haptic_pulse_mode mode;
|
||||
enum max77693_haptic_pwm_divisor pwm_divisor;
|
||||
|
||||
struct work_struct work;
|
||||
};
|
||||
@@ -78,19 +82,52 @@ static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77843_haptic_bias(struct max77693_haptic *haptic, bool on)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (haptic->dev_type != TYPE_MAX77843)
|
||||
return 0;
|
||||
|
||||
error = regmap_update_bits(haptic->regmap_haptic,
|
||||
MAX77843_SYS_REG_MAINCTRL1,
|
||||
MAX77843_MAINCTRL1_BIASEN_MASK,
|
||||
on << MAINCTRL1_BIASEN_SHIFT);
|
||||
if (error) {
|
||||
dev_err(haptic->dev, "failed to %s bias: %d\n",
|
||||
on ? "enable" : "disable", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77693_haptic_configure(struct max77693_haptic *haptic,
|
||||
bool enable)
|
||||
{
|
||||
unsigned int value;
|
||||
unsigned int value, config_reg;
|
||||
int error;
|
||||
|
||||
value = ((haptic->type << MAX77693_CONFIG2_MODE) |
|
||||
(enable << MAX77693_CONFIG2_MEN) |
|
||||
(haptic->mode << MAX77693_CONFIG2_HTYP) |
|
||||
(haptic->pwm_divisor));
|
||||
switch (haptic->dev_type) {
|
||||
case TYPE_MAX77693:
|
||||
value = ((haptic->type << MAX77693_CONFIG2_MODE) |
|
||||
(enable << MAX77693_CONFIG2_MEN) |
|
||||
(haptic->mode << MAX77693_CONFIG2_HTYP) |
|
||||
MAX77693_HAPTIC_PWM_DIVISOR_128);
|
||||
config_reg = MAX77693_HAPTIC_REG_CONFIG2;
|
||||
break;
|
||||
case TYPE_MAX77843:
|
||||
value = (haptic->type << MCONFIG_MODE_SHIFT) |
|
||||
(enable << MCONFIG_MEN_SHIFT) |
|
||||
MAX77693_HAPTIC_PWM_DIVISOR_128;
|
||||
config_reg = MAX77843_HAP_REG_MCONFIG;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = regmap_write(haptic->regmap_haptic,
|
||||
MAX77693_HAPTIC_REG_CONFIG2, value);
|
||||
config_reg, value);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
"failed to update haptic config: %d\n", error);
|
||||
@@ -104,6 +141,9 @@ static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (haptic->dev_type != TYPE_MAX77693)
|
||||
return 0;
|
||||
|
||||
error = regmap_update_bits(haptic->regmap_pmic,
|
||||
MAX77693_PMIC_REG_LSCNFG,
|
||||
MAX77693_PMIC_LOW_SYS_MASK,
|
||||
@@ -219,6 +259,10 @@ static int max77693_haptic_open(struct input_dev *dev)
|
||||
struct max77693_haptic *haptic = input_get_drvdata(dev);
|
||||
int error;
|
||||
|
||||
error = max77843_haptic_bias(haptic, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = regulator_enable(haptic->motor_reg);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
@@ -241,6 +285,8 @@ static void max77693_haptic_close(struct input_dev *dev)
|
||||
if (error)
|
||||
dev_err(haptic->dev,
|
||||
"failed to disable regulator: %d\n", error);
|
||||
|
||||
max77843_haptic_bias(haptic, false);
|
||||
}
|
||||
|
||||
static int max77693_haptic_probe(struct platform_device *pdev)
|
||||
@@ -254,13 +300,26 @@ static int max77693_haptic_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
haptic->regmap_pmic = max77693->regmap;
|
||||
haptic->regmap_haptic = max77693->regmap_haptic;
|
||||
haptic->dev = &pdev->dev;
|
||||
haptic->type = MAX77693_HAPTIC_LRA;
|
||||
haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
|
||||
haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
|
||||
haptic->suspend_state = false;
|
||||
|
||||
/* Variant-specific init */
|
||||
haptic->dev_type = platform_get_device_id(pdev)->driver_data;
|
||||
switch (haptic->dev_type) {
|
||||
case TYPE_MAX77693:
|
||||
haptic->regmap_haptic = max77693->regmap_haptic;
|
||||
break;
|
||||
case TYPE_MAX77843:
|
||||
haptic->regmap_haptic = max77693->regmap;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "unsupported device type: %u\n",
|
||||
haptic->dev_type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
INIT_WORK(&haptic->work, max77693_haptic_play_work);
|
||||
|
||||
/* Get pwm and regulatot for haptic device */
|
||||
@@ -338,16 +397,25 @@ static int __maybe_unused max77693_haptic_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
|
||||
max77693_haptic_suspend, max77693_haptic_resume);
|
||||
|
||||
static const struct platform_device_id max77693_haptic_id[] = {
|
||||
{ "max77693-haptic", TYPE_MAX77693 },
|
||||
{ "max77843-haptic", TYPE_MAX77843 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max77693_haptic_id);
|
||||
|
||||
static struct platform_driver max77693_haptic_driver = {
|
||||
.driver = {
|
||||
.name = "max77693-haptic",
|
||||
.pm = &max77693_haptic_pm_ops,
|
||||
},
|
||||
.probe = max77693_haptic_probe,
|
||||
.id_table = max77693_haptic_id,
|
||||
};
|
||||
module_platform_driver(max77693_haptic_driver);
|
||||
|
||||
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
|
||||
MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver");
|
||||
MODULE_ALIAS("platform:max77693-haptic");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* MAXIM MAX77693 Haptic device driver
|
||||
*
|
||||
* Copyright (C) 2015 Samsung Electronics
|
||||
* Author: Jaewon Kim <jaewon02.kim@samsung.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/max77843-private.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define MAX_MAGNITUDE_SHIFT 16
|
||||
|
||||
enum max77843_haptic_motor_type {
|
||||
MAX77843_HAPTIC_ERM = 0,
|
||||
MAX77843_HAPTIC_LRA,
|
||||
};
|
||||
|
||||
enum max77843_haptic_pwm_divisor {
|
||||
MAX77843_HAPTIC_PWM_DIVISOR_32 = 0,
|
||||
MAX77843_HAPTIC_PWM_DIVISOR_64,
|
||||
MAX77843_HAPTIC_PWM_DIVISOR_128,
|
||||
MAX77843_HAPTIC_PWM_DIVISOR_256,
|
||||
};
|
||||
|
||||
struct max77843_haptic {
|
||||
struct regmap *regmap_haptic;
|
||||
struct device *dev;
|
||||
struct input_dev *input_dev;
|
||||
struct pwm_device *pwm_dev;
|
||||
struct regulator *motor_reg;
|
||||
struct work_struct work;
|
||||
struct mutex mutex;
|
||||
|
||||
unsigned int magnitude;
|
||||
unsigned int pwm_duty;
|
||||
|
||||
bool active;
|
||||
bool suspended;
|
||||
|
||||
enum max77843_haptic_motor_type type;
|
||||
enum max77843_haptic_pwm_divisor pwm_divisor;
|
||||
};
|
||||
|
||||
static int max77843_haptic_set_duty_cycle(struct max77843_haptic *haptic)
|
||||
{
|
||||
int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2;
|
||||
int error;
|
||||
|
||||
error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
|
||||
if (error) {
|
||||
dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77843_haptic_bias(struct max77843_haptic *haptic, bool on)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = regmap_update_bits(haptic->regmap_haptic,
|
||||
MAX77843_SYS_REG_MAINCTRL1,
|
||||
MAX77843_MAINCTRL1_BIASEN_MASK,
|
||||
on << MAINCTRL1_BIASEN_SHIFT);
|
||||
if (error) {
|
||||
dev_err(haptic->dev, "failed to %s bias: %d\n",
|
||||
on ? "enable" : "disable", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77843_haptic_config(struct max77843_haptic *haptic, bool enable)
|
||||
{
|
||||
unsigned int value;
|
||||
int error;
|
||||
|
||||
value = (haptic->type << MCONFIG_MODE_SHIFT) |
|
||||
(enable << MCONFIG_MEN_SHIFT) |
|
||||
(haptic->pwm_divisor << MCONFIG_PDIV_SHIFT);
|
||||
|
||||
error = regmap_write(haptic->regmap_haptic,
|
||||
MAX77843_HAP_REG_MCONFIG, value);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
"failed to update haptic config: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77843_haptic_enable(struct max77843_haptic *haptic)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (haptic->active)
|
||||
return 0;
|
||||
|
||||
error = pwm_enable(haptic->pwm_dev);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
"failed to enable pwm device: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
error = max77843_haptic_config(haptic, true);
|
||||
if (error)
|
||||
goto err_config;
|
||||
|
||||
haptic->active = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_config:
|
||||
pwm_disable(haptic->pwm_dev);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int max77843_haptic_disable(struct max77843_haptic *haptic)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!haptic->active)
|
||||
return 0;
|
||||
|
||||
error = max77843_haptic_config(haptic, false);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
pwm_disable(haptic->pwm_dev);
|
||||
|
||||
haptic->active = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max77843_haptic_play_work(struct work_struct *work)
|
||||
{
|
||||
struct max77843_haptic *haptic =
|
||||
container_of(work, struct max77843_haptic, work);
|
||||
int error;
|
||||
|
||||
mutex_lock(&haptic->mutex);
|
||||
|
||||
if (haptic->suspended)
|
||||
goto out_unlock;
|
||||
|
||||
if (haptic->magnitude) {
|
||||
error = max77843_haptic_set_duty_cycle(haptic);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
"failed to set duty cycle: %d\n", error);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
error = max77843_haptic_enable(haptic);
|
||||
if (error)
|
||||
dev_err(haptic->dev,
|
||||
"cannot enable haptic: %d\n", error);
|
||||
} else {
|
||||
error = max77843_haptic_disable(haptic);
|
||||
if (error)
|
||||
dev_err(haptic->dev,
|
||||
"cannot disable haptic: %d\n", error);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&haptic->mutex);
|
||||
}
|
||||
|
||||
static int max77843_haptic_play_effect(struct input_dev *dev, void *data,
|
||||
struct ff_effect *effect)
|
||||
{
|
||||
struct max77843_haptic *haptic = input_get_drvdata(dev);
|
||||
u64 period_mag_multi;
|
||||
|
||||
haptic->magnitude = effect->u.rumble.strong_magnitude;
|
||||
if (!haptic->magnitude)
|
||||
haptic->magnitude = effect->u.rumble.weak_magnitude;
|
||||
|
||||
period_mag_multi = (u64)haptic->pwm_dev->period * haptic->magnitude;
|
||||
haptic->pwm_duty = (unsigned int)(period_mag_multi >>
|
||||
MAX_MAGNITUDE_SHIFT);
|
||||
|
||||
schedule_work(&haptic->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max77843_haptic_open(struct input_dev *dev)
|
||||
{
|
||||
struct max77843_haptic *haptic = input_get_drvdata(dev);
|
||||
int error;
|
||||
|
||||
error = max77843_haptic_bias(haptic, true);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = regulator_enable(haptic->motor_reg);
|
||||
if (error) {
|
||||
dev_err(haptic->dev,
|
||||
"failed to enable regulator: %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max77843_haptic_close(struct input_dev *dev)
|
||||
{
|
||||
struct max77843_haptic *haptic = input_get_drvdata(dev);
|
||||
int error;
|
||||
|
||||
cancel_work_sync(&haptic->work);
|
||||
max77843_haptic_disable(haptic);
|
||||
|
||||
error = regulator_disable(haptic->motor_reg);
|
||||
if (error)
|
||||
dev_err(haptic->dev,
|
||||
"failed to disable regulator: %d\n", error);
|
||||
|
||||
max77843_haptic_bias(haptic, false);
|
||||
}
|
||||
|
||||
static int max77843_haptic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max77843_haptic *haptic;
|
||||
int error;
|
||||
|
||||
haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
|
||||
if (!haptic)
|
||||
return -ENOMEM;
|
||||
|
||||
haptic->regmap_haptic = max77843->regmap;
|
||||
haptic->dev = &pdev->dev;
|
||||
haptic->type = MAX77843_HAPTIC_LRA;
|
||||
haptic->pwm_divisor = MAX77843_HAPTIC_PWM_DIVISOR_128;
|
||||
|
||||
INIT_WORK(&haptic->work, max77843_haptic_play_work);
|
||||
mutex_init(&haptic->mutex);
|
||||
|
||||
haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(haptic->pwm_dev)) {
|
||||
dev_err(&pdev->dev, "failed to get pwm device\n");
|
||||
return PTR_ERR(haptic->pwm_dev);
|
||||
}
|
||||
|
||||
haptic->motor_reg = devm_regulator_get_exclusive(&pdev->dev, "haptic");
|
||||
if (IS_ERR(haptic->motor_reg)) {
|
||||
dev_err(&pdev->dev, "failed to get regulator\n");
|
||||
return PTR_ERR(haptic->motor_reg);
|
||||
}
|
||||
|
||||
haptic->input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!haptic->input_dev) {
|
||||
dev_err(&pdev->dev, "failed to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
haptic->input_dev->name = "max77843-haptic";
|
||||
haptic->input_dev->id.version = 1;
|
||||
haptic->input_dev->dev.parent = &pdev->dev;
|
||||
haptic->input_dev->open = max77843_haptic_open;
|
||||
haptic->input_dev->close = max77843_haptic_close;
|
||||
input_set_drvdata(haptic->input_dev, haptic);
|
||||
input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
|
||||
|
||||
error = input_ff_create_memless(haptic->input_dev, NULL,
|
||||
max77843_haptic_play_effect);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to create force-feedback\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
error = input_register_device(haptic->input_dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register input device\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, haptic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused max77843_haptic_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct max77843_haptic *haptic = platform_get_drvdata(pdev);
|
||||
int error;
|
||||
|
||||
error = mutex_lock_interruptible(&haptic->mutex);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
max77843_haptic_disable(haptic);
|
||||
|
||||
haptic->suspended = true;
|
||||
|
||||
mutex_unlock(&haptic->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused max77843_haptic_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct max77843_haptic *haptic = platform_get_drvdata(pdev);
|
||||
unsigned int magnitude;
|
||||
|
||||
mutex_lock(&haptic->mutex);
|
||||
|
||||
haptic->suspended = false;
|
||||
|
||||
magnitude = ACCESS_ONCE(haptic->magnitude);
|
||||
if (magnitude)
|
||||
max77843_haptic_enable(haptic);
|
||||
|
||||
mutex_unlock(&haptic->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max77843_haptic_pm_ops,
|
||||
max77843_haptic_suspend, max77843_haptic_resume);
|
||||
|
||||
static struct platform_driver max77843_haptic_driver = {
|
||||
.driver = {
|
||||
.name = "max77843-haptic",
|
||||
.pm = &max77843_haptic_pm_ops,
|
||||
},
|
||||
.probe = max77843_haptic_probe,
|
||||
};
|
||||
module_platform_driver(max77843_haptic_driver);
|
||||
|
||||
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("MAXIM MAX77843 Haptic driver");
|
||||
MODULE_LICENSE("GPL");
|
@@ -7,6 +7,7 @@
|
||||
#include <linux/input-polldev.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
|
||||
#include <asm/mach-rc32434/gpio.h>
|
||||
#include <asm/mach-rc32434/rb.h>
|
||||
|
@@ -183,7 +183,8 @@ static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
|
||||
if (pdata && pdata->coexist)
|
||||
return true;
|
||||
|
||||
if (of_find_node_by_name(node, "codec")) {
|
||||
node = of_find_node_by_name(node, "codec");
|
||||
if (node) {
|
||||
of_node_put(node);
|
||||
return true;
|
||||
}
|
||||
|
@@ -232,7 +232,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
|
||||
struct xenbus_transaction xbt;
|
||||
|
||||
ret = gnttab_grant_foreign_access(dev->otherend_id,
|
||||
virt_to_mfn(info->page), 0);
|
||||
virt_to_gfn(info->page), 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
info->gref = ret;
|
||||
@@ -255,7 +255,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
|
||||
goto error_irqh;
|
||||
}
|
||||
ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
|
||||
virt_to_mfn(info->page));
|
||||
virt_to_gfn(info->page));
|
||||
if (ret)
|
||||
goto error_xenbus;
|
||||
ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref);
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/libps2.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include "psmouse.h"
|
||||
#include "alps.h"
|
||||
@@ -99,6 +100,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
|
||||
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
|
||||
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
|
||||
6-byte ALPS packet */
|
||||
#define ALPS_DELL 0x100 /* device is a Dell laptop */
|
||||
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
|
||||
|
||||
static const struct alps_model_info alps_model_data[] = {
|
||||
@@ -251,9 +253,9 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Non interleaved V2 dualpoint has separate stick button bits */
|
||||
/* Dell non interleaved V2 dualpoint has separate stick button bits */
|
||||
if (priv->proto_version == ALPS_PROTO_V2 &&
|
||||
priv->flags == (ALPS_PASS | ALPS_DUALPOINT)) {
|
||||
priv->flags == (ALPS_DELL | ALPS_PASS | ALPS_DUALPOINT)) {
|
||||
left |= packet[0] & 1;
|
||||
right |= packet[0] & 2;
|
||||
middle |= packet[0] & 4;
|
||||
@@ -2550,6 +2552,8 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
priv->byte0 = protocol->byte0;
|
||||
priv->mask0 = protocol->mask0;
|
||||
priv->flags = protocol->flags;
|
||||
if (dmi_name_in_vendors("Dell"))
|
||||
priv->flags |= ALPS_DELL;
|
||||
|
||||
priv->x_max = 2000;
|
||||
priv->y_max = 1400;
|
||||
|
@@ -2,6 +2,7 @@
|
||||
* Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
|
||||
*
|
||||
* Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
|
||||
* Copyright (C) 2015 John Horan (knasher@gmail.com)
|
||||
*
|
||||
* The USB initialization and package decoding was made by
|
||||
* Scott Shawcroft as part of the touchd user-space driver project:
|
||||
@@ -91,6 +92,10 @@
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292
|
||||
/* MacbookPro12,1 (2015) */
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
|
||||
#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
|
||||
|
||||
#define BCM5974_DEVICE(prod) { \
|
||||
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
|
||||
@@ -152,6 +157,10 @@ static const struct usb_device_id bcm5974_table[] = {
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
|
||||
/* MacbookPro12,1 */
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI),
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_ISO),
|
||||
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
|
||||
/* Terminating entry */
|
||||
{}
|
||||
};
|
||||
@@ -180,21 +189,47 @@ struct bt_data {
|
||||
enum tp_type {
|
||||
TYPE1, /* plain trackpad */
|
||||
TYPE2, /* button integrated in trackpad */
|
||||
TYPE3 /* additional header fields since June 2013 */
|
||||
TYPE3, /* additional header fields since June 2013 */
|
||||
TYPE4 /* additional header field for pressure data */
|
||||
};
|
||||
|
||||
/* trackpad finger data offsets, le16-aligned */
|
||||
#define FINGER_TYPE1 (13 * sizeof(__le16))
|
||||
#define FINGER_TYPE2 (15 * sizeof(__le16))
|
||||
#define FINGER_TYPE3 (19 * sizeof(__le16))
|
||||
#define HEADER_TYPE1 (13 * sizeof(__le16))
|
||||
#define HEADER_TYPE2 (15 * sizeof(__le16))
|
||||
#define HEADER_TYPE3 (19 * sizeof(__le16))
|
||||
#define HEADER_TYPE4 (23 * sizeof(__le16))
|
||||
|
||||
/* trackpad button data offsets */
|
||||
#define BUTTON_TYPE1 0
|
||||
#define BUTTON_TYPE2 15
|
||||
#define BUTTON_TYPE3 23
|
||||
#define BUTTON_TYPE4 31
|
||||
|
||||
/* list of device capability bits */
|
||||
#define HAS_INTEGRATED_BUTTON 1
|
||||
|
||||
/* trackpad finger data block size */
|
||||
#define FSIZE_TYPE1 (14 * sizeof(__le16))
|
||||
#define FSIZE_TYPE2 (14 * sizeof(__le16))
|
||||
#define FSIZE_TYPE3 (14 * sizeof(__le16))
|
||||
#define FSIZE_TYPE4 (15 * sizeof(__le16))
|
||||
|
||||
/* offset from header to finger struct */
|
||||
#define DELTA_TYPE1 (0 * sizeof(__le16))
|
||||
#define DELTA_TYPE2 (0 * sizeof(__le16))
|
||||
#define DELTA_TYPE3 (0 * sizeof(__le16))
|
||||
#define DELTA_TYPE4 (1 * sizeof(__le16))
|
||||
|
||||
/* usb control message mode switch data */
|
||||
#define USBMSG_TYPE1 8, 0x300, 0, 0, 0x1, 0x8
|
||||
#define USBMSG_TYPE2 8, 0x300, 0, 0, 0x1, 0x8
|
||||
#define USBMSG_TYPE3 8, 0x300, 0, 0, 0x1, 0x8
|
||||
#define USBMSG_TYPE4 2, 0x302, 2, 1, 0x1, 0x0
|
||||
|
||||
/* Wellspring initialization constants */
|
||||
#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
|
||||
#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
|
||||
|
||||
/* trackpad finger structure, le16-aligned */
|
||||
struct tp_finger {
|
||||
__le16 origin; /* zero when switching track finger */
|
||||
@@ -207,14 +242,13 @@ struct tp_finger {
|
||||
__le16 orientation; /* 16384 when point, else 15 bit angle */
|
||||
__le16 touch_major; /* touch area, major axis */
|
||||
__le16 touch_minor; /* touch area, minor axis */
|
||||
__le16 unused[3]; /* zeros */
|
||||
__le16 unused[2]; /* zeros */
|
||||
__le16 pressure; /* pressure on forcetouch touchpad */
|
||||
__le16 multi; /* one finger: varies, more fingers: constant */
|
||||
} __attribute__((packed,aligned(2)));
|
||||
|
||||
/* trackpad finger data size, empirically at least ten fingers */
|
||||
#define MAX_FINGERS 16
|
||||
#define SIZEOF_FINGER sizeof(struct tp_finger)
|
||||
#define SIZEOF_ALL_FINGERS (MAX_FINGERS * SIZEOF_FINGER)
|
||||
#define MAX_FINGER_ORIENTATION 16384
|
||||
|
||||
/* device-specific parameters */
|
||||
@@ -232,8 +266,17 @@ struct bcm5974_config {
|
||||
int bt_datalen; /* data length of the button interface */
|
||||
int tp_ep; /* the endpoint of the trackpad interface */
|
||||
enum tp_type tp_type; /* type of trackpad interface */
|
||||
int tp_offset; /* offset to trackpad finger data */
|
||||
int tp_header; /* bytes in header block */
|
||||
int tp_datalen; /* data length of the trackpad interface */
|
||||
int tp_button; /* offset to button data */
|
||||
int tp_fsize; /* bytes in single finger block */
|
||||
int tp_delta; /* offset from header to finger struct */
|
||||
int um_size; /* usb control message length */
|
||||
int um_req_val; /* usb control message value */
|
||||
int um_req_idx; /* usb control message index */
|
||||
int um_switch_idx; /* usb control message mode switch index */
|
||||
int um_switch_on; /* usb control message mode switch on */
|
||||
int um_switch_off; /* usb control message mode switch off */
|
||||
struct bcm5974_param p; /* finger pressure limits */
|
||||
struct bcm5974_param w; /* finger width limits */
|
||||
struct bcm5974_param x; /* horizontal limits */
|
||||
@@ -259,6 +302,24 @@ struct bcm5974 {
|
||||
int slots[MAX_FINGERS]; /* slot assignments */
|
||||
};
|
||||
|
||||
/* trackpad finger block data, le16-aligned */
|
||||
static const struct tp_finger *get_tp_finger(const struct bcm5974 *dev, int i)
|
||||
{
|
||||
const struct bcm5974_config *c = &dev->cfg;
|
||||
u8 *f_base = dev->tp_data + c->tp_header + c->tp_delta;
|
||||
|
||||
return (const struct tp_finger *)(f_base + i * c->tp_fsize);
|
||||
}
|
||||
|
||||
#define DATAFORMAT(type) \
|
||||
type, \
|
||||
HEADER_##type, \
|
||||
HEADER_##type + (MAX_FINGERS) * (FSIZE_##type), \
|
||||
BUTTON_##type, \
|
||||
FSIZE_##type, \
|
||||
DELTA_##type, \
|
||||
USBMSG_##type
|
||||
|
||||
/* logical signal quality */
|
||||
#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
|
||||
#define SN_WIDTH 25 /* width signal-to-noise ratio */
|
||||
@@ -273,7 +334,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
|
||||
0,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE1),
|
||||
{ SN_PRESSURE, 0, 256 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4824, 5342 },
|
||||
@@ -286,7 +347,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
|
||||
0,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE1),
|
||||
{ SN_PRESSURE, 0, 256 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4824, 4824 },
|
||||
@@ -299,7 +360,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING3_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4460, 5166 },
|
||||
@@ -312,7 +373,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING4_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
@@ -325,7 +386,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4616, 5112 },
|
||||
@@ -338,7 +399,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING5_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4415, 5050 },
|
||||
@@ -351,7 +412,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
@@ -364,7 +425,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4750, 5280 },
|
||||
@@ -377,7 +438,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
@@ -390,7 +451,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING7_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4750, 5280 },
|
||||
@@ -403,7 +464,7 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0x84, sizeof(struct bt_data),
|
||||
0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
|
||||
0x81, DATAFORMAT(TYPE2),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4750, 5280 },
|
||||
@@ -416,13 +477,26 @@ static const struct bcm5974_config bcm5974_config_table[] = {
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0, sizeof(struct bt_data),
|
||||
0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
|
||||
0x83, DATAFORMAT(TYPE3),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4620, 5140 },
|
||||
{ SN_COORD, -150, 6600 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI,
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING9_ISO,
|
||||
USB_DEVICE_ID_APPLE_WELLSPRING9_JIS,
|
||||
HAS_INTEGRATED_BUTTON,
|
||||
0, sizeof(struct bt_data),
|
||||
0x83, DATAFORMAT(TYPE4),
|
||||
{ SN_PRESSURE, 0, 300 },
|
||||
{ SN_WIDTH, 0, 2048 },
|
||||
{ SN_COORD, -4828, 5345 },
|
||||
{ SN_COORD, -203, 6803 },
|
||||
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -549,19 +623,18 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
||||
struct input_dev *input = dev->input;
|
||||
int raw_n, i, n = 0;
|
||||
|
||||
if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)
|
||||
if (size < c->tp_header || (size - c->tp_header) % c->tp_fsize != 0)
|
||||
return -EIO;
|
||||
|
||||
/* finger data, le16-aligned */
|
||||
f = (const struct tp_finger *)(dev->tp_data + c->tp_offset);
|
||||
raw_n = (size - c->tp_offset) / SIZEOF_FINGER;
|
||||
raw_n = (size - c->tp_header) / c->tp_fsize;
|
||||
|
||||
for (i = 0; i < raw_n; i++) {
|
||||
if (raw2int(f[i].touch_major) == 0)
|
||||
f = get_tp_finger(dev, i);
|
||||
if (raw2int(f->touch_major) == 0)
|
||||
continue;
|
||||
dev->pos[n].x = raw2int(f[i].abs_x);
|
||||
dev->pos[n].y = c->y.min + c->y.max - raw2int(f[i].abs_y);
|
||||
dev->index[n++] = &f[i];
|
||||
dev->pos[n].x = raw2int(f->abs_x);
|
||||
dev->pos[n].y = c->y.min + c->y.max - raw2int(f->abs_y);
|
||||
dev->index[n++] = f;
|
||||
}
|
||||
|
||||
input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
|
||||
@@ -572,32 +645,22 @@ static int report_tp_state(struct bcm5974 *dev, int size)
|
||||
|
||||
input_mt_sync_frame(input);
|
||||
|
||||
report_synaptics_data(input, c, f, raw_n);
|
||||
report_synaptics_data(input, c, get_tp_finger(dev, 0), raw_n);
|
||||
|
||||
/* type 2 reports button events via ibt only */
|
||||
if (c->tp_type == TYPE2) {
|
||||
int ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);
|
||||
/* later types report button events via integrated button only */
|
||||
if (c->caps & HAS_INTEGRATED_BUTTON) {
|
||||
int ibt = raw2int(dev->tp_data[c->tp_button]);
|
||||
input_report_key(input, BTN_LEFT, ibt);
|
||||
}
|
||||
|
||||
if (c->tp_type == TYPE3)
|
||||
input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
|
||||
|
||||
input_sync(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wellspring initialization constants */
|
||||
#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
|
||||
#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
|
||||
#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300
|
||||
#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0
|
||||
#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01
|
||||
#define BCM5974_WELLSPRING_MODE_NORMAL_VALUE 0x08
|
||||
|
||||
static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
|
||||
{
|
||||
const struct bcm5974_config *c = &dev->cfg;
|
||||
int retval = 0, size;
|
||||
char *data;
|
||||
|
||||
@@ -605,7 +668,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
|
||||
if (dev->cfg.tp_type == TYPE3)
|
||||
return 0;
|
||||
|
||||
data = kmalloc(8, GFP_KERNEL);
|
||||
data = kmalloc(c->um_size, GFP_KERNEL);
|
||||
if (!data) {
|
||||
dev_err(&dev->intf->dev, "out of memory\n");
|
||||
retval = -ENOMEM;
|
||||
@@ -616,28 +679,24 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
|
||||
size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
|
||||
BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
|
||||
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
|
||||
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
|
||||
c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
|
||||
|
||||
if (size != 8) {
|
||||
if (size != c->um_size) {
|
||||
dev_err(&dev->intf->dev, "could not read from device\n");
|
||||
retval = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* apply the mode switch */
|
||||
data[0] = on ?
|
||||
BCM5974_WELLSPRING_MODE_VENDOR_VALUE :
|
||||
BCM5974_WELLSPRING_MODE_NORMAL_VALUE;
|
||||
data[c->um_switch_idx] = on ? c->um_switch_on : c->um_switch_off;
|
||||
|
||||
/* write configuration */
|
||||
size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
|
||||
BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
|
||||
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
|
||||
BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
|
||||
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
|
||||
c->um_req_val, c->um_req_idx, data, c->um_size, 5000);
|
||||
|
||||
if (size != 8) {
|
||||
if (size != c->um_size) {
|
||||
dev_err(&dev->intf->dev, "could not write to device\n");
|
||||
retval = -EIO;
|
||||
goto out;
|
||||
|
@@ -783,19 +783,26 @@ static int elantech_packet_check_v4(struct psmouse *psmouse)
|
||||
struct elantech_data *etd = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
unsigned char packet_type = packet[3] & 0x03;
|
||||
unsigned int ic_version;
|
||||
bool sanity_check;
|
||||
|
||||
if (etd->tp_dev && (packet[3] & 0x0f) == 0x06)
|
||||
return PACKET_TRACKPOINT;
|
||||
|
||||
/* This represents the version of IC body. */
|
||||
ic_version = (etd->fw_version & 0x0f0000) >> 16;
|
||||
|
||||
/*
|
||||
* Sanity check based on the constant bits of a packet.
|
||||
* The constant bits change depending on the value of
|
||||
* the hardware flag 'crc_enabled' but are the same for
|
||||
* every packet, regardless of the type.
|
||||
* the hardware flag 'crc_enabled' and the version of
|
||||
* the IC body, but are the same for every packet,
|
||||
* regardless of the type.
|
||||
*/
|
||||
if (etd->crc_enabled)
|
||||
sanity_check = ((packet[3] & 0x08) == 0x00);
|
||||
else if (ic_version == 7 && etd->samples[1] == 0x2A)
|
||||
sanity_check = ((packet[3] & 0x1c) == 0x10);
|
||||
else
|
||||
sanity_check = ((packet[0] & 0x0c) == 0x04 &&
|
||||
(packet[3] & 0x1c) == 0x10);
|
||||
@@ -1116,6 +1123,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
|
||||
* Avatar AVIU-145A2 0x361f00 ? clickpad
|
||||
* Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
|
||||
* Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
|
||||
* Fujitsu T725 0x470f01 05, 12, 09 2 hw buttons
|
||||
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
|
||||
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
|
||||
* Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
|
||||
@@ -1167,7 +1175,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct elantech_data *etd = psmouse->private;
|
||||
unsigned int x_min = 0, y_min = 0, x_max = 0, y_max = 0, width = 0;
|
||||
unsigned int x_res = 0, y_res = 0;
|
||||
unsigned int x_res = 31, y_res = 31;
|
||||
|
||||
if (elantech_set_range(psmouse, &x_min, &y_min, &x_max, &y_max, &width))
|
||||
return -1;
|
||||
@@ -1232,8 +1240,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||||
/* For X to recognize me as touchpad. */
|
||||
input_set_abs_params(dev, ABS_X, x_min, x_max, 0, 0);
|
||||
input_set_abs_params(dev, ABS_Y, y_min, y_max, 0, 0);
|
||||
input_abs_set_res(dev, ABS_X, x_res);
|
||||
input_abs_set_res(dev, ABS_Y, y_res);
|
||||
/*
|
||||
* range of pressure and width is the same as v2,
|
||||
* report ABS_PRESSURE, ABS_TOOL_WIDTH for compatibility.
|
||||
@@ -1246,8 +1252,6 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||||
input_mt_init_slots(dev, ETP_MAX_FINGERS, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_X, x_min, x_max, 0, 0);
|
||||
input_set_abs_params(dev, ABS_MT_POSITION_Y, y_min, y_max, 0, 0);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
|
||||
input_set_abs_params(dev, ABS_MT_PRESSURE, ETP_PMIN_V2,
|
||||
ETP_PMAX_V2, 0, 0);
|
||||
/*
|
||||
@@ -1259,6 +1263,13 @@ static int elantech_set_input_params(struct psmouse *psmouse)
|
||||
break;
|
||||
}
|
||||
|
||||
input_abs_set_res(dev, ABS_X, x_res);
|
||||
input_abs_set_res(dev, ABS_Y, y_res);
|
||||
if (etd->hw_version > 1) {
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_X, x_res);
|
||||
input_abs_set_res(dev, ABS_MT_POSITION_Y, y_res);
|
||||
}
|
||||
|
||||
etd->y_max = y_max;
|
||||
etd->width = width;
|
||||
|
||||
@@ -1648,6 +1659,16 @@ int elantech_init(struct psmouse *psmouse)
|
||||
etd->capabilities[0], etd->capabilities[1],
|
||||
etd->capabilities[2]);
|
||||
|
||||
if (etd->hw_version != 1) {
|
||||
if (etd->send_cmd(psmouse, ETP_SAMPLE_QUERY, etd->samples)) {
|
||||
psmouse_err(psmouse, "failed to query sample data\n");
|
||||
goto init_fail;
|
||||
}
|
||||
psmouse_info(psmouse,
|
||||
"Elan sample query result %02x, %02x, %02x\n",
|
||||
etd->samples[0], etd->samples[1], etd->samples[2]);
|
||||
}
|
||||
|
||||
if (elantech_set_absolute_mode(psmouse)) {
|
||||
psmouse_err(psmouse,
|
||||
"failed to put touchpad into absolute mode.\n");
|
||||
|
@@ -129,6 +129,7 @@ struct elantech_data {
|
||||
unsigned char reg_26;
|
||||
unsigned char debug;
|
||||
unsigned char capabilities[3];
|
||||
unsigned char samples[3];
|
||||
bool paritycheck;
|
||||
bool jumpy_cursor;
|
||||
bool reports_pressure;
|
||||
|
@@ -519,14 +519,18 @@ static int synaptics_set_mode(struct psmouse *psmouse)
|
||||
struct synaptics_data *priv = psmouse->private;
|
||||
|
||||
priv->mode = 0;
|
||||
if (priv->absolute_mode)
|
||||
|
||||
if (priv->absolute_mode) {
|
||||
priv->mode |= SYN_BIT_ABSOLUTE_MODE;
|
||||
if (priv->disable_gesture)
|
||||
if (SYN_CAP_EXTENDED(priv->capabilities))
|
||||
priv->mode |= SYN_BIT_W_MODE;
|
||||
}
|
||||
|
||||
if (!SYN_MODE_WMODE(priv->mode) && priv->disable_gesture)
|
||||
priv->mode |= SYN_BIT_DISABLE_GESTURE;
|
||||
|
||||
if (psmouse->rate >= 80)
|
||||
priv->mode |= SYN_BIT_HIGH_RATE;
|
||||
if (SYN_CAP_EXTENDED(priv->capabilities))
|
||||
priv->mode |= SYN_BIT_W_MODE;
|
||||
|
||||
if (synaptics_mode_cmd(psmouse, priv->mode))
|
||||
return -1;
|
||||
@@ -1484,12 +1488,12 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode)
|
||||
priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS;
|
||||
|
||||
psmouse_info(psmouse,
|
||||
"Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
|
||||
"Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n",
|
||||
SYN_ID_MODEL(priv->identity),
|
||||
SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
|
||||
priv->model_id,
|
||||
priv->capabilities, priv->ext_cap, priv->ext_cap_0c,
|
||||
priv->board_id, priv->firmware_id);
|
||||
priv->ext_cap_10, priv->board_id, priv->firmware_id);
|
||||
|
||||
set_input_params(psmouse, priv);
|
||||
|
||||
|
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
@@ -34,6 +35,7 @@ struct goodix_ts_data {
|
||||
int abs_y_max;
|
||||
unsigned int max_touch_num;
|
||||
unsigned int int_trigger_type;
|
||||
bool rotated_screen;
|
||||
};
|
||||
|
||||
#define GOODIX_MAX_HEIGHT 4096
|
||||
@@ -60,6 +62,30 @@ static const unsigned long goodix_irq_flags[] = {
|
||||
IRQ_TYPE_LEVEL_HIGH,
|
||||
};
|
||||
|
||||
/*
|
||||
* Those tablets have their coordinates origin at the bottom right
|
||||
* of the tablet, as if rotated 180 degrees
|
||||
*/
|
||||
static const struct dmi_system_id rotated_screen[] = {
|
||||
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
|
||||
{
|
||||
.ident = "WinBook TW100",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TW100")
|
||||
}
|
||||
},
|
||||
{
|
||||
.ident = "WinBook TW700",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "WinBook"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TW700")
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* goodix_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
@@ -129,6 +155,11 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
int input_y = get_unaligned_le16(&coor_data[3]);
|
||||
int input_w = get_unaligned_le16(&coor_data[5]);
|
||||
|
||||
if (ts->rotated_screen) {
|
||||
input_x = ts->abs_x_max - input_x;
|
||||
input_y = ts->abs_y_max - input_y;
|
||||
}
|
||||
|
||||
input_mt_slot(ts->input_dev, id);
|
||||
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
|
||||
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
|
||||
@@ -223,6 +254,11 @@ static void goodix_read_config(struct goodix_ts_data *ts)
|
||||
ts->abs_y_max = GOODIX_MAX_HEIGHT;
|
||||
ts->max_touch_num = GOODIX_MAX_CONTACTS;
|
||||
}
|
||||
|
||||
ts->rotated_screen = dmi_check_system(rotated_screen);
|
||||
if (ts->rotated_screen)
|
||||
dev_dbg(&ts->client->dev,
|
||||
"Applying '180 degrees rotated screen' quirk\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -216,7 +216,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,
|
||||
/* get panel info */
|
||||
error = ili210x_read_reg(client, REG_PANEL_INFO, &panel, sizeof(panel));
|
||||
if (error) {
|
||||
dev_err(dev, "Failed to get panel informations, err: %d\n",
|
||||
dev_err(dev, "Failed to get panel information, err: %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
@@ -276,7 +276,7 @@ static int ili210x_i2c_probe(struct i2c_client *client,
|
||||
|
||||
error = input_register_device(priv->input);
|
||||
if (error) {
|
||||
dev_err(dev, "Cannot regiser input device, err: %d\n", error);
|
||||
dev_err(dev, "Cannot register input device, err: %d\n", error);
|
||||
goto err_remove_sysfs;
|
||||
}
|
||||
|
||||
|
@@ -191,7 +191,7 @@ static void sun4i_ts_close(struct input_dev *dev)
|
||||
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
|
||||
}
|
||||
|
||||
static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
|
||||
static int sun4i_get_temp(const struct sun4i_ts_data *ts, int *temp)
|
||||
{
|
||||
/* No temp_data until the first irq */
|
||||
if (ts->temp_data == -1)
|
||||
@@ -202,7 +202,7 @@ static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_get_tz_temp(void *data, long *temp)
|
||||
static int sun4i_get_tz_temp(void *data, int *temp)
|
||||
{
|
||||
return sun4i_get_temp(data, temp);
|
||||
}
|
||||
@@ -215,14 +215,14 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
|
||||
char *buf)
|
||||
{
|
||||
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
|
||||
long temp;
|
||||
int temp;
|
||||
int error;
|
||||
|
||||
error = sun4i_get_temp(ts, &temp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return sprintf(buf, "%ld\n", temp);
|
||||
return sprintf(buf, "%d\n", temp);
|
||||
}
|
||||
|
||||
static ssize_t show_temp_label(struct device *dev,
|
||||
|
@@ -627,6 +627,9 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* TSC-25 data sheet specifies a delay after the RESET command */
|
||||
msleep(150);
|
||||
|
||||
/* set coordinate output rate */
|
||||
buf[0] = buf[1] = 0xFF;
|
||||
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
|
||||
|
@@ -732,8 +732,7 @@ static int wm97xx_remove(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm97xx_suspend(struct device *dev, pm_message_t state)
|
||||
static int __maybe_unused wm97xx_suspend(struct device *dev)
|
||||
{
|
||||
struct wm97xx *wm = dev_get_drvdata(dev);
|
||||
u16 reg;
|
||||
@@ -765,7 +764,7 @@ static int wm97xx_suspend(struct device *dev, pm_message_t state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm97xx_resume(struct device *dev)
|
||||
static int __maybe_unused wm97xx_resume(struct device *dev)
|
||||
{
|
||||
struct wm97xx *wm = dev_get_drvdata(dev);
|
||||
|
||||
@@ -799,10 +798,7 @@ static int wm97xx_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define wm97xx_suspend NULL
|
||||
#define wm97xx_resume NULL
|
||||
#endif
|
||||
static SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
|
||||
|
||||
/*
|
||||
* Machine specific operations
|
||||
@@ -836,8 +832,7 @@ static struct device_driver wm97xx_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.probe = wm97xx_probe,
|
||||
.remove = wm97xx_remove,
|
||||
.suspend = wm97xx_suspend,
|
||||
.resume = wm97xx_resume,
|
||||
.pm = &wm97xx_pm_ops,
|
||||
};
|
||||
|
||||
static int __init wm97xx_init(void)
|
||||
|
Reference in New Issue
Block a user