diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/gameport/gameport.c | 4 | ||||
-rw-r--r-- | drivers/input/joystick/analog.c | 4 | ||||
-rw-r--r-- | drivers/input/joystick/turbografx.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 11 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys_polled.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/snvs_pwrkey.c | 227 | ||||
-rw-r--r-- | drivers/input/misc/Kconfig | 18 | ||||
-rw-r--r-- | drivers/input/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/misc/axp20x-pek.c | 1 | ||||
-rw-r--r-- | drivers/input/misc/max77693-haptic.c | 92 | ||||
-rw-r--r-- | drivers/input/misc/max77843-haptic.c | 358 | ||||
-rw-r--r-- | drivers/input/misc/twl4030-vibra.c | 3 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 8 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 22 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.h | 1 |
16 files changed, 358 insertions, 397 deletions
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index e853a2134680..4a2a9e370be7 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -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; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 4284080e481d..6f8b084e13d0 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -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) diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 27b6a3ce18ca..891797ad76bc 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -196,7 +196,7 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs) 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]); err = -EINVAL; goto err_unreg_devs; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 4cd94fd6cbad..82a8fb50afac 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -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 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index df28d5553c05..1d416ddf84e4 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -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 diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 097d7216d98e..c6dc644aa580 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -246,7 +246,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; diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c new file mode 100644 index 000000000000..78fd24ca3813 --- /dev/null +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -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"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d4f0a817e858..c41dec819cdf 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -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 diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 53df07dcc23c..0357a088c6a9 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -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 diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 10e140af5aac..1ac898db303a 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -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"); diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index 39e930c10ebb..6d96bff32a0e 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -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"); diff --git a/drivers/input/misc/max77843-haptic.c b/drivers/input/misc/max77843-haptic.c deleted file mode 100644 index dccbb465a055..000000000000 --- a/drivers/input/misc/max77843-haptic.c +++ /dev/null @@ -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"); diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index fc17b9592f54..10c4e3d462f1 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -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; } diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 113d6f1516a5..4d246861d692 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -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; diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 22b9ca901f4e..2955f1d0ca6c 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -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 (*) @@ -1651,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"); diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index f965d1569cc3..e1cbf409d9c8 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -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; |