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:
Dmitry Torokhov
2015-09-29 16:28:52 -07:00
10159 changed files with 562719 additions and 255386 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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