From 934df23171e7c5b71d937104d4957891c39748ff Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Fri, 17 Feb 2017 12:51:19 -0800 Subject: Input: tsc2007 - check for presence and power down tsc2007 during probe 1. check if chip is really present and don't succeed if it isn't. 2. if it succeeds, power down the chip until accessed Signed-off-by: H. Nikolaus Schaller Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 5d0cd51c6f41..a4b7b4c3d27b 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -455,6 +455,14 @@ static int tsc2007_probe(struct i2c_client *client, tsc2007_stop(ts); + /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + dev_err(&client->dev, + "Failed to setup chip: %d\n", err); + return err; /* usually, chip does not respond */ + } + err = input_register_device(input_dev); if (err) { dev_err(&client->dev, -- cgit From f14434040ce0d1bcaac167fb08286e31d48ca9a5 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Fri, 17 Feb 2017 12:53:32 -0800 Subject: Input: tsc2007 - add iio interface to read external ADC input and temperature The tsc2007 chip not only has a resistive touch screen controller but also an external AUX adc imput which can be used for an ambient light sensor, battery voltage monitoring or any general purpose. Additionally it can measure the chip temperature. This extension provides an iio interface for these adc channels. Since it is not wasting much resources and is very straightforward, we simply provide all other adc channels as optional iio interfaces as weel. This can be used for debugging or special applications. This patch also splits the tsc2007 driver in several source files: tsc2007.h -- constants, structs and stubs tsc2007_core.c -- functional parts of the original driver tsc2007_iio.c -- the optional iio stuff Makefile magic allows to conditionally link the iio stuff if CONFIG_IIO=y or =m in a way that it works with CONFIG_TOUCHSCREEN_TSC2007=m. Signed-off-by: H. Nikolaus Schaller Reviewed-by: Jonathan Cameron Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 2 + drivers/input/touchscreen/tsc2007.c | 504 ------------------------------- drivers/input/touchscreen/tsc2007.h | 102 +++++++ drivers/input/touchscreen/tsc2007_core.c | 457 ++++++++++++++++++++++++++++ drivers/input/touchscreen/tsc2007_iio.c | 140 +++++++++ 6 files changed, 711 insertions(+), 504 deletions(-) delete mode 100644 drivers/input/touchscreen/tsc2007.c create mode 100644 drivers/input/touchscreen/tsc2007.h create mode 100644 drivers/input/touchscreen/tsc2007_core.c create mode 100644 drivers/input/touchscreen/tsc2007_iio.c (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index efca0133e266..1616a8d0bc7c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1035,6 +1035,16 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_TSC2007_IIO + bool "IIO interface for external ADC input and temperature" + depends on TOUCHSCREEN_TSC2007 + depends on IIO=y || IIO=TOUCHSCREEN_TSC2007 + help + Saying Y here adds an iio interface to the tsc2007 which + provides values for the AUX input (used for e.g. battery + or ambient light monitoring), temperature and raw input + values. + config TOUCHSCREEN_W90X900 tristate "W90P910 touchscreen driver" depends on ARCH_W90X900 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 81b86451782d..05d1cc88b919 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -80,6 +80,8 @@ obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o +tsc2007-y := tsc2007_core.o +tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c deleted file mode 100644 index a4b7b4c3d27b..000000000000 --- a/drivers/input/touchscreen/tsc2007.c +++ /dev/null @@ -1,504 +0,0 @@ -/* - * drivers/input/touchscreen/tsc2007.c - * - * Copyright (c) 2008 MtekVision Co., Ltd. - * Kwangwoo Lee - * - * Using code from: - * - ads7846.c - * Copyright (c) 2005 David Brownell - * Copyright (c) 2006 Nokia Corporation - * - corgi_ts.c - * Copyright (C) 2004-2005 Richard Purdie - * - omap_ts.[hc], ads7846.h, ts_osk.c - * Copyright (C) 2002 MontaVista Software - * Copyright (C) 2004 Texas Instruments - * Copyright (C) 2005 Dirk Behme - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TSC2007_MEASURE_TEMP0 (0x0 << 4) -#define TSC2007_MEASURE_AUX (0x2 << 4) -#define TSC2007_MEASURE_TEMP1 (0x4 << 4) -#define TSC2007_ACTIVATE_XN (0x8 << 4) -#define TSC2007_ACTIVATE_YN (0x9 << 4) -#define TSC2007_ACTIVATE_YP_XN (0xa << 4) -#define TSC2007_SETUP (0xb << 4) -#define TSC2007_MEASURE_X (0xc << 4) -#define TSC2007_MEASURE_Y (0xd << 4) -#define TSC2007_MEASURE_Z1 (0xe << 4) -#define TSC2007_MEASURE_Z2 (0xf << 4) - -#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2) -#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2) -#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2) -#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2) - -#define TSC2007_12BIT (0x0 << 1) -#define TSC2007_8BIT (0x1 << 1) - -#define MAX_12BIT ((1 << 12) - 1) - -#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0) - -#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y) -#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1) -#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2) -#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X) -#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN) - -struct ts_event { - u16 x; - u16 y; - u16 z1, z2; -}; - -struct tsc2007 { - struct input_dev *input; - char phys[32]; - - struct i2c_client *client; - - u16 model; - u16 x_plate_ohms; - u16 max_rt; - unsigned long poll_period; /* in jiffies */ - int fuzzx; - int fuzzy; - int fuzzz; - - unsigned gpio; - int irq; - - wait_queue_head_t wait; - bool stopped; - - int (*get_pendown_state)(struct device *); - void (*clear_penirq)(void); -}; - -static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) -{ - s32 data; - u16 val; - - data = i2c_smbus_read_word_data(tsc->client, cmd); - if (data < 0) { - dev_err(&tsc->client->dev, "i2c io error: %d\n", data); - return data; - } - - /* The protocol and raw data format from i2c interface: - * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P - * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit]. - */ - val = swab16(data) >> 4; - - dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val); - - return val; -} - -static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) -{ - /* y- still on; turn on only y+ (and ADC) */ - tc->y = tsc2007_xfer(tsc, READ_Y); - - /* turn y- off, x+ on, then leave in lowpower */ - tc->x = tsc2007_xfer(tsc, READ_X); - - /* turn y+ off, x- on; we'll use formula #1 */ - tc->z1 = tsc2007_xfer(tsc, READ_Z1); - tc->z2 = tsc2007_xfer(tsc, READ_Z2); - - /* Prepare for next touch reading - power down ADC, enable PENIRQ */ - tsc2007_xfer(tsc, PWRDOWN); -} - -static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) -{ - u32 rt = 0; - - /* range filtering */ - if (tc->x == MAX_12BIT) - tc->x = 0; - - if (likely(tc->x && tc->z1)) { - /* compute touch pressure resistance using equation #1 */ - rt = tc->z2 - tc->z1; - rt *= tc->x; - rt *= tsc->x_plate_ohms; - rt /= tc->z1; - rt = (rt + 2047) >> 12; - } - - return rt; -} - -static bool tsc2007_is_pen_down(struct tsc2007 *ts) -{ - /* - * NOTE: We can't rely on the pressure to determine the pen down - * state, even though this controller has a pressure sensor. - * The pressure value can fluctuate for quite a while after - * lifting the pen and in some cases may not even settle at the - * expected value. - * - * The only safe way to check for the pen up condition is in the - * work function by reading the pen signal state (it's a GPIO - * and IRQ). Unfortunately such callback is not always available, - * in that case we assume that the pen is down and expect caller - * to fall back on the pressure reading. - */ - - if (!ts->get_pendown_state) - return true; - - return ts->get_pendown_state(&ts->client->dev); -} - -static irqreturn_t tsc2007_soft_irq(int irq, void *handle) -{ - struct tsc2007 *ts = handle; - struct input_dev *input = ts->input; - struct ts_event tc; - u32 rt; - - while (!ts->stopped && tsc2007_is_pen_down(ts)) { - - /* pen is down, continue with the measurement */ - tsc2007_read_values(ts, &tc); - - rt = tsc2007_calculate_pressure(ts, &tc); - - if (!rt && !ts->get_pendown_state) { - /* - * If pressure reported is 0 and we don't have - * callback to check pendown state, we have to - * assume that pen was lifted up. - */ - break; - } - - if (rt <= ts->max_rt) { - dev_dbg(&ts->client->dev, - "DOWN point(%4d,%4d), pressure (%4u)\n", - tc.x, tc.y, rt); - - input_report_key(input, BTN_TOUCH, 1); - input_report_abs(input, ABS_X, tc.x); - input_report_abs(input, ABS_Y, tc.y); - input_report_abs(input, ABS_PRESSURE, rt); - - input_sync(input); - - } else { - /* - * Sample found inconsistent by debouncing or pressure is - * beyond the maximum. Don't report it to user space, - * repeat at least once more the measurement. - */ - dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); - } - - wait_event_timeout(ts->wait, ts->stopped, ts->poll_period); - } - - dev_dbg(&ts->client->dev, "UP\n"); - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); - - if (ts->clear_penirq) - ts->clear_penirq(); - - return IRQ_HANDLED; -} - -static irqreturn_t tsc2007_hard_irq(int irq, void *handle) -{ - struct tsc2007 *ts = handle; - - if (tsc2007_is_pen_down(ts)) - return IRQ_WAKE_THREAD; - - if (ts->clear_penirq) - ts->clear_penirq(); - - return IRQ_HANDLED; -} - -static void tsc2007_stop(struct tsc2007 *ts) -{ - ts->stopped = true; - mb(); - wake_up(&ts->wait); - - disable_irq(ts->irq); -} - -static int tsc2007_open(struct input_dev *input_dev) -{ - struct tsc2007 *ts = input_get_drvdata(input_dev); - int err; - - ts->stopped = false; - mb(); - - enable_irq(ts->irq); - - /* Prepare for touch readings - power down ADC and enable PENIRQ */ - err = tsc2007_xfer(ts, PWRDOWN); - if (err < 0) { - tsc2007_stop(ts); - return err; - } - - return 0; -} - -static void tsc2007_close(struct input_dev *input_dev) -{ - struct tsc2007 *ts = input_get_drvdata(input_dev); - - tsc2007_stop(ts); -} - -#ifdef CONFIG_OF -static int tsc2007_get_pendown_state_gpio(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct tsc2007 *ts = i2c_get_clientdata(client); - - return !gpio_get_value(ts->gpio); -} - -static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) -{ - struct device_node *np = client->dev.of_node; - u32 val32; - u64 val64; - - if (!np) { - dev_err(&client->dev, "missing device tree data\n"); - return -EINVAL; - } - - if (!of_property_read_u32(np, "ti,max-rt", &val32)) - ts->max_rt = val32; - else - ts->max_rt = MAX_12BIT; - - if (!of_property_read_u32(np, "ti,fuzzx", &val32)) - ts->fuzzx = val32; - - if (!of_property_read_u32(np, "ti,fuzzy", &val32)) - ts->fuzzy = val32; - - if (!of_property_read_u32(np, "ti,fuzzz", &val32)) - ts->fuzzz = val32; - - if (!of_property_read_u64(np, "ti,poll-period", &val64)) - ts->poll_period = msecs_to_jiffies(val64); - else - ts->poll_period = msecs_to_jiffies(1); - - if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { - ts->x_plate_ohms = val32; - } else { - dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); - return -EINVAL; - } - - ts->gpio = of_get_gpio(np, 0); - if (gpio_is_valid(ts->gpio)) - ts->get_pendown_state = tsc2007_get_pendown_state_gpio; - else - dev_warn(&client->dev, - "GPIO not specified in DT (of_get_gpio returned %d)\n", - ts->gpio); - - return 0; -} -#else -static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) -{ - dev_err(&client->dev, "platform data is required!\n"); - return -EINVAL; -} -#endif - -static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, - const struct tsc2007_platform_data *pdata, - const struct i2c_device_id *id) -{ - ts->model = pdata->model; - ts->x_plate_ohms = pdata->x_plate_ohms; - ts->max_rt = pdata->max_rt ? : MAX_12BIT; - ts->poll_period = msecs_to_jiffies(pdata->poll_period ? : 1); - ts->get_pendown_state = pdata->get_pendown_state; - ts->clear_penirq = pdata->clear_penirq; - ts->fuzzx = pdata->fuzzx; - ts->fuzzy = pdata->fuzzy; - ts->fuzzz = pdata->fuzzz; - - if (pdata->x_plate_ohms == 0) { - dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); - return -EINVAL; - } - - return 0; -} - -static void tsc2007_call_exit_platform_hw(void *data) -{ - struct device *dev = data; - const struct tsc2007_platform_data *pdata = dev_get_platdata(dev); - - pdata->exit_platform_hw(); -} - -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); - struct tsc2007 *ts; - struct input_dev *input_dev; - int err; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -EIO; - - ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); - if (!ts) - return -ENOMEM; - - if (pdata) - err = tsc2007_probe_pdev(client, ts, pdata, id); - else - err = tsc2007_probe_dt(client, ts); - if (err) - return err; - - input_dev = devm_input_allocate_device(&client->dev); - if (!input_dev) - return -ENOMEM; - - i2c_set_clientdata(client, ts); - - ts->client = client; - ts->irq = client->irq; - ts->input = input_dev; - init_waitqueue_head(&ts->wait); - - snprintf(ts->phys, sizeof(ts->phys), - "%s/input0", dev_name(&client->dev)); - - input_dev->name = "TSC2007 Touchscreen"; - input_dev->phys = ts->phys; - input_dev->id.bustype = BUS_I2C; - - input_dev->open = tsc2007_open; - input_dev->close = tsc2007_close; - - input_set_drvdata(input_dev, ts); - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); - input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, - ts->fuzzz, 0); - - if (pdata) { - if (pdata->exit_platform_hw) { - err = devm_add_action(&client->dev, - tsc2007_call_exit_platform_hw, - &client->dev); - if (err) { - dev_err(&client->dev, - "Failed to register exit_platform_hw action, %d\n", - err); - return err; - } - } - - if (pdata->init_platform_hw) - pdata->init_platform_hw(); - } - - err = devm_request_threaded_irq(&client->dev, ts->irq, - tsc2007_hard_irq, tsc2007_soft_irq, - IRQF_ONESHOT, - client->dev.driver->name, ts); - if (err) { - dev_err(&client->dev, "Failed to request irq %d: %d\n", - ts->irq, err); - return err; - } - - tsc2007_stop(ts); - - /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ - err = tsc2007_xfer(ts, PWRDOWN); - if (err < 0) { - dev_err(&client->dev, - "Failed to setup chip: %d\n", err); - return err; /* usually, chip does not respond */ - } - - err = input_register_device(input_dev); - if (err) { - dev_err(&client->dev, - "Failed to register input device: %d\n", err); - return err; - } - - return 0; -} - -static const struct i2c_device_id tsc2007_idtable[] = { - { "tsc2007", 0 }, - { } -}; - -MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); - -#ifdef CONFIG_OF -static const struct of_device_id tsc2007_of_match[] = { - { .compatible = "ti,tsc2007" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, tsc2007_of_match); -#endif - -static struct i2c_driver tsc2007_driver = { - .driver = { - .name = "tsc2007", - .of_match_table = of_match_ptr(tsc2007_of_match), - }, - .id_table = tsc2007_idtable, - .probe = tsc2007_probe, -}; - -module_i2c_driver(tsc2007_driver); - -MODULE_AUTHOR("Kwangwoo Lee "); -MODULE_DESCRIPTION("TSC2007 TouchScreen Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h new file mode 100644 index 000000000000..474bd29d6242 --- /dev/null +++ b/drivers/input/touchscreen/tsc2007.h @@ -0,0 +1,102 @@ + +/* + * Copyright (c) 2008 MtekVision Co., Ltd. + * Kwangwoo Lee + * + * Using code from: + * - ads7846.c + * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * - corgi_ts.c + * Copyright (C) 2004-2005 Richard Purdie + * - omap_ts.[hc], ads7846.h, ts_osk.c + * Copyright (C) 2002 MontaVista Software + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2005 Dirk Behme + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TSC2007_H +#define _TSC2007_H + +#define TSC2007_MEASURE_TEMP0 (0x0 << 4) +#define TSC2007_MEASURE_AUX (0x2 << 4) +#define TSC2007_MEASURE_TEMP1 (0x4 << 4) +#define TSC2007_ACTIVATE_XN (0x8 << 4) +#define TSC2007_ACTIVATE_YN (0x9 << 4) +#define TSC2007_ACTIVATE_YP_XN (0xa << 4) +#define TSC2007_SETUP (0xb << 4) +#define TSC2007_MEASURE_X (0xc << 4) +#define TSC2007_MEASURE_Y (0xd << 4) +#define TSC2007_MEASURE_Z1 (0xe << 4) +#define TSC2007_MEASURE_Z2 (0xf << 4) + +#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2) +#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2) +#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2) +#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2) + +#define TSC2007_12BIT (0x0 << 1) +#define TSC2007_8BIT (0x1 << 1) + +#define MAX_12BIT ((1 << 12) - 1) + +#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0) + +#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y) +#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1) +#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2) +#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X) +#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN) + +struct ts_event { + u16 x; + u16 y; + u16 z1, z2; +}; + +struct tsc2007 { + struct input_dev *input; + char phys[32]; + + struct i2c_client *client; + + u16 model; + u16 x_plate_ohms; + u16 max_rt; + unsigned long poll_period; /* in jiffies */ + int fuzzx; + int fuzzy; + int fuzzz; + + unsigned int gpio; + int irq; + + wait_queue_head_t wait; + bool stopped; + + int (*get_pendown_state)(struct device *); + void (*clear_penirq)(void); + + struct mutex mlock; +}; + +int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd); +u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, + struct ts_event *tc); +bool tsc2007_is_pen_down(struct tsc2007 *ts); + +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007_IIO) +/* defined in tsc2007_iio.c */ +int tsc2007_iio_configure(struct tsc2007 *ts); +#else +static inline int tsc2007_iio_configure(struct tsc2007 *ts) +{ + return 0; +} +#endif /* CONFIG_TOUCHSCREEN_TSC2007_IIO */ + +#endif /* _TSC2007_H */ diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c new file mode 100644 index 000000000000..fdf81a2b989a --- /dev/null +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -0,0 +1,457 @@ +/* + * drivers/input/touchscreen/tsc2007.c + * + * Copyright (c) 2008 MtekVision Co., Ltd. + * Kwangwoo Lee + * + * Using code from: + * - ads7846.c + * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * - corgi_ts.c + * Copyright (C) 2004-2005 Richard Purdie + * - omap_ts.[hc], ads7846.h, ts_osk.c + * Copyright (C) 2002 MontaVista Software + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2005 Dirk Behme + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "tsc2007.h" + +int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) +{ + s32 data; + u16 val; + + data = i2c_smbus_read_word_data(tsc->client, cmd); + if (data < 0) { + dev_err(&tsc->client->dev, "i2c io error: %d\n", data); + return data; + } + + /* The protocol and raw data format from i2c interface: + * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P + * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit]. + */ + val = swab16(data) >> 4; + + dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x\n", data, val); + + return val; +} + +static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) +{ + /* y- still on; turn on only y+ (and ADC) */ + tc->y = tsc2007_xfer(tsc, READ_Y); + + /* turn y- off, x+ on, then leave in lowpower */ + tc->x = tsc2007_xfer(tsc, READ_X); + + /* turn y+ off, x- on; we'll use formula #1 */ + tc->z1 = tsc2007_xfer(tsc, READ_Z1); + tc->z2 = tsc2007_xfer(tsc, READ_Z2); + + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); +} + +u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +{ + u32 rt = 0; + + /* range filtering */ + if (tc->x == MAX_12BIT) + tc->x = 0; + + if (likely(tc->x && tc->z1)) { + /* compute touch pressure resistance using equation #1 */ + rt = tc->z2 - tc->z1; + rt *= tc->x; + rt *= tsc->x_plate_ohms; + rt /= tc->z1; + rt = (rt + 2047) >> 12; + } + + return rt; +} + +bool tsc2007_is_pen_down(struct tsc2007 *ts) +{ + /* + * NOTE: We can't rely on the pressure to determine the pen down + * state, even though this controller has a pressure sensor. + * The pressure value can fluctuate for quite a while after + * lifting the pen and in some cases may not even settle at the + * expected value. + * + * The only safe way to check for the pen up condition is in the + * work function by reading the pen signal state (it's a GPIO + * and IRQ). Unfortunately such callback is not always available, + * in that case we assume that the pen is down and expect caller + * to fall back on the pressure reading. + */ + + if (!ts->get_pendown_state) + return true; + + return ts->get_pendown_state(&ts->client->dev); +} + +static irqreturn_t tsc2007_soft_irq(int irq, void *handle) +{ + struct tsc2007 *ts = handle; + struct input_dev *input = ts->input; + struct ts_event tc; + u32 rt; + + while (!ts->stopped && tsc2007_is_pen_down(ts)) { + + /* pen is down, continue with the measurement */ + + mutex_lock(&ts->mlock); + tsc2007_read_values(ts, &tc); + mutex_unlock(&ts->mlock); + + rt = tsc2007_calculate_pressure(ts, &tc); + + if (!rt && !ts->get_pendown_state) { + /* + * If pressure reported is 0 and we don't have + * callback to check pendown state, we have to + * assume that pen was lifted up. + */ + break; + } + + if (rt <= ts->max_rt) { + dev_dbg(&ts->client->dev, + "DOWN point(%4d,%4d), pressure (%4u)\n", + tc.x, tc.y, rt); + + input_report_key(input, BTN_TOUCH, 1); + input_report_abs(input, ABS_X, tc.x); + input_report_abs(input, ABS_Y, tc.y); + input_report_abs(input, ABS_PRESSURE, rt); + + input_sync(input); + + } else { + /* + * Sample found inconsistent by debouncing or pressure is + * beyond the maximum. Don't report it to user space, + * repeat at least once more the measurement. + */ + dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); + } + + wait_event_timeout(ts->wait, ts->stopped, ts->poll_period); + } + + dev_dbg(&ts->client->dev, "UP\n"); + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); + + if (ts->clear_penirq) + ts->clear_penirq(); + + return IRQ_HANDLED; +} + +static irqreturn_t tsc2007_hard_irq(int irq, void *handle) +{ + struct tsc2007 *ts = handle; + + if (tsc2007_is_pen_down(ts)) + return IRQ_WAKE_THREAD; + + if (ts->clear_penirq) + ts->clear_penirq(); + + return IRQ_HANDLED; +} + +static void tsc2007_stop(struct tsc2007 *ts) +{ + ts->stopped = true; + mb(); + wake_up(&ts->wait); + + disable_irq(ts->irq); +} + +static int tsc2007_open(struct input_dev *input_dev) +{ + struct tsc2007 *ts = input_get_drvdata(input_dev); + int err; + + ts->stopped = false; + mb(); + + enable_irq(ts->irq); + + /* Prepare for touch readings - power down ADC and enable PENIRQ */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + tsc2007_stop(ts); + return err; + } + + return 0; +} + +static void tsc2007_close(struct input_dev *input_dev) +{ + struct tsc2007 *ts = input_get_drvdata(input_dev); + + tsc2007_stop(ts); +} + +#ifdef CONFIG_OF +static int tsc2007_get_pendown_state_gpio(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tsc2007 *ts = i2c_get_clientdata(client); + + return !gpio_get_value(ts->gpio); +} + +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + struct device_node *np = client->dev.of_node; + u32 val32; + u64 val64; + + if (!np) { + dev_err(&client->dev, "missing device tree data\n"); + return -EINVAL; + } + + if (!of_property_read_u32(np, "ti,max-rt", &val32)) + ts->max_rt = val32; + else + ts->max_rt = MAX_12BIT; + + if (!of_property_read_u32(np, "ti,fuzzx", &val32)) + ts->fuzzx = val32; + + if (!of_property_read_u32(np, "ti,fuzzy", &val32)) + ts->fuzzy = val32; + + if (!of_property_read_u32(np, "ti,fuzzz", &val32)) + ts->fuzzz = val32; + + if (!of_property_read_u64(np, "ti,poll-period", &val64)) + ts->poll_period = msecs_to_jiffies(val64); + else + ts->poll_period = msecs_to_jiffies(1); + + if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { + ts->x_plate_ohms = val32; + } else { + dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); + return -EINVAL; + } + + ts->gpio = of_get_gpio(np, 0); + if (gpio_is_valid(ts->gpio)) + ts->get_pendown_state = tsc2007_get_pendown_state_gpio; + else + dev_warn(&client->dev, + "GPIO not specified in DT (of_get_gpio returned %d)\n", + ts->gpio); + + return 0; +} +#else +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + dev_err(&client->dev, "platform data is required!\n"); + return -EINVAL; +} +#endif + +static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, + const struct tsc2007_platform_data *pdata, + const struct i2c_device_id *id) +{ + ts->model = pdata->model; + ts->x_plate_ohms = pdata->x_plate_ohms; + ts->max_rt = pdata->max_rt ? : MAX_12BIT; + ts->poll_period = msecs_to_jiffies(pdata->poll_period ? : 1); + ts->get_pendown_state = pdata->get_pendown_state; + ts->clear_penirq = pdata->clear_penirq; + ts->fuzzx = pdata->fuzzx; + ts->fuzzy = pdata->fuzzy; + ts->fuzzz = pdata->fuzzz; + + if (pdata->x_plate_ohms == 0) { + dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); + return -EINVAL; + } + + return 0; +} + +static void tsc2007_call_exit_platform_hw(void *data) +{ + struct device *dev = data; + const struct tsc2007_platform_data *pdata = dev_get_platdata(dev); + + pdata->exit_platform_hw(); +} + +static int tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct tsc2007_platform_data *pdata = + dev_get_platdata(&client->dev); + struct tsc2007 *ts; + struct input_dev *input_dev; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EIO; + + ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + if (pdata) + err = tsc2007_probe_pdev(client, ts, pdata, id); + else + err = tsc2007_probe_dt(client, ts); + if (err) + return err; + + input_dev = devm_input_allocate_device(&client->dev); + if (!input_dev) + return -ENOMEM; + + i2c_set_clientdata(client, ts); + + ts->client = client; + ts->irq = client->irq; + ts->input = input_dev; + + init_waitqueue_head(&ts->wait); + mutex_init(&ts->mlock); + + snprintf(ts->phys, sizeof(ts->phys), + "%s/input0", dev_name(&client->dev)); + + input_dev->name = "TSC2007 Touchscreen"; + input_dev->phys = ts->phys; + input_dev->id.bustype = BUS_I2C; + + input_dev->open = tsc2007_open; + input_dev->close = tsc2007_close; + + input_set_drvdata(input_dev, ts); + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, + ts->fuzzz, 0); + + if (pdata) { + if (pdata->exit_platform_hw) { + err = devm_add_action(&client->dev, + tsc2007_call_exit_platform_hw, + &client->dev); + if (err) { + dev_err(&client->dev, + "Failed to register exit_platform_hw action, %d\n", + err); + return err; + } + } + + if (pdata->init_platform_hw) + pdata->init_platform_hw(); + } + + err = devm_request_threaded_irq(&client->dev, ts->irq, + tsc2007_hard_irq, tsc2007_soft_irq, + IRQF_ONESHOT, + client->dev.driver->name, ts); + if (err) { + dev_err(&client->dev, "Failed to request irq %d: %d\n", + ts->irq, err); + return err; + } + + tsc2007_stop(ts); + + /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + dev_err(&client->dev, + "Failed to setup chip: %d\n", err); + return err; /* chip does not respond */ + } + + err = input_register_device(input_dev); + if (err) { + dev_err(&client->dev, + "Failed to register input device: %d\n", err); + return err; + } + + err = tsc2007_iio_configure(ts); + if (err) { + dev_err(&client->dev, + "Failed to register with IIO: %d\n", err); + return err; + } + + return 0; +} + +static const struct i2c_device_id tsc2007_idtable[] = { + { "tsc2007", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); + +#ifdef CONFIG_OF +static const struct of_device_id tsc2007_of_match[] = { + { .compatible = "ti,tsc2007" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2007_of_match); +#endif + +static struct i2c_driver tsc2007_driver = { + .driver = { + .name = "tsc2007", + .of_match_table = of_match_ptr(tsc2007_of_match), + }, + .id_table = tsc2007_idtable, + .probe = tsc2007_probe, +}; + +module_i2c_driver(tsc2007_driver); + +MODULE_AUTHOR("Kwangwoo Lee "); +MODULE_DESCRIPTION("TSC2007 TouchScreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c new file mode 100644 index 000000000000..0ec3f28d0457 --- /dev/null +++ b/drivers/input/touchscreen/tsc2007_iio.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG + * Nikolaus Schaller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include "tsc2007.h" + +struct tsc2007_iio { + struct tsc2007 *ts; +}; + +#define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \ +{ \ + .datasheet_name = _name, \ + .type = _type, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(_chan_info), \ + .indexed = 1, \ + .channel = _chan, \ +} + +static const struct iio_chan_spec tsc2007_iio_channel[] = { + TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */ + TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW), +}; + +static int tsc2007_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tsc2007_iio *iio = iio_priv(indio_dev); + struct tsc2007 *tsc = iio->ts; + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel)) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + mutex_lock(&tsc->mlock); + + switch (chan->channel) { + case 0: + *val = tsc2007_xfer(tsc, READ_X); + break; + case 1: + *val = tsc2007_xfer(tsc, READ_Y); + break; + case 2: + *val = tsc2007_xfer(tsc, READ_Z1); + break; + case 3: + *val = tsc2007_xfer(tsc, READ_Z2); + break; + case 4: + *val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX)); + break; + case 5: { + struct ts_event tc; + + tc.x = tsc2007_xfer(tsc, READ_X); + tc.z1 = tsc2007_xfer(tsc, READ_Z1); + tc.z2 = tsc2007_xfer(tsc, READ_Z2); + *val = tsc2007_calculate_pressure(tsc, &tc); + break; + } + case 6: + *val = tsc2007_is_pen_down(tsc); + break; + case 7: + *val = tsc2007_xfer(tsc, + (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0)); + break; + case 8: + *val = tsc2007_xfer(tsc, + (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1)); + break; + } + + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); + + mutex_unlock(&tsc->mlock); + + ret = IIO_VAL_INT; + + return ret; +} + +static const struct iio_info tsc2007_iio_info = { + .read_raw = tsc2007_read_raw, + .driver_module = THIS_MODULE, +}; + +int tsc2007_iio_configure(struct tsc2007 *ts) +{ + struct iio_dev *indio_dev; + struct tsc2007_iio *iio; + int error; + + indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio)); + if (!indio_dev) { + dev_err(&ts->client->dev, "iio_device_alloc failed\n"); + return -ENOMEM; + } + + iio = iio_priv(indio_dev); + iio->ts = ts; + + indio_dev->name = "tsc2007"; + indio_dev->dev.parent = &ts->client->dev; + indio_dev->info = &tsc2007_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = tsc2007_iio_channel; + indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel); + + error = devm_iio_device_register(&ts->client->dev, indio_dev); + if (error) { + dev_err(&ts->client->dev, + "iio_device_register() failed: %d\n", error); + return error; + } + + return 0; +} -- cgit From c61ebe83e7fba0ad4d88dc114121cf8ff7ca8d47 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Feb 2017 14:51:13 -0800 Subject: Input: tsc2007 - switch to using input_set_capability() Do not manipulate evbits/keybits directly, use helper for that. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index fdf81a2b989a..98dbefc3357d 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -364,8 +364,7 @@ static int tsc2007_probe(struct i2c_client *client, input_set_drvdata(input_dev, ts); - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); -- cgit From deec586d4fcbc14a262f8b887543abcb1c64af98 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Wed, 22 Feb 2017 23:49:02 -0800 Subject: Input: tsc2007 - rename function tsc2007_calculate_pressure Rename tsc2007_calculate_pressure to tsc2007_calculate_resistance because that is what it does. Signed-off-by: H. Nikolaus Schaller Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.h | 3 +-- drivers/input/touchscreen/tsc2007_core.c | 8 ++++---- drivers/input/touchscreen/tsc2007_iio.c | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h index 474bd29d6242..30fdf5b04a6b 100644 --- a/drivers/input/touchscreen/tsc2007.h +++ b/drivers/input/touchscreen/tsc2007.h @@ -85,8 +85,7 @@ struct tsc2007 { }; int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd); -u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, - struct ts_event *tc); +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc); bool tsc2007_is_pen_down(struct tsc2007 *ts); #if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007_IIO) diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 98dbefc3357d..30b53ca95aec 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -68,7 +68,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) tsc2007_xfer(tsc, PWRDOWN); } -u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) { u32 rt = 0; @@ -77,7 +77,7 @@ u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) tc->x = 0; if (likely(tc->x && tc->z1)) { - /* compute touch pressure resistance using equation #1 */ + /* compute touch resistance using equation #1 */ rt = tc->z2 - tc->z1; rt *= tc->x; rt *= tsc->x_plate_ohms; @@ -125,7 +125,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) tsc2007_read_values(ts, &tc); mutex_unlock(&ts->mlock); - rt = tsc2007_calculate_pressure(ts, &tc); + rt = tsc2007_calculate_resistance(ts, &tc); if (!rt && !ts->get_pendown_state) { /* @@ -138,7 +138,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) if (rt <= ts->max_rt) { dev_dbg(&ts->client->dev, - "DOWN point(%4d,%4d), pressure (%4u)\n", + "DOWN point(%4d,%4d), resistance (%4u)\n", tc.x, tc.y, rt); input_report_key(input, BTN_TOUCH, 1); diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c index 0ec3f28d0457..27b25a9fce83 100644 --- a/drivers/input/touchscreen/tsc2007_iio.c +++ b/drivers/input/touchscreen/tsc2007_iio.c @@ -76,7 +76,7 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev, tc.x = tsc2007_xfer(tsc, READ_X); tc.z1 = tsc2007_xfer(tsc, READ_Z1); tc.z2 = tsc2007_xfer(tsc, READ_Z2); - *val = tsc2007_calculate_pressure(tsc, &tc); + *val = tsc2007_calculate_resistance(tsc, &tc); break; } case 6: -- cgit From db4572ff0e2a017ea73ab532ed5257d7be351c88 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Wed, 22 Feb 2017 23:53:02 -0800 Subject: Input: tsc2007 - correctly report pressure and not resistance to user space Previously, tsc2007 would report as ABS_PRESSURE: 0 for no pressure (resistance infinite) high value for soft pressure (high resistance) low value for firm pressure (lower resistance) This does not matter for most applications (e.g. GUI, Menu, Scrolling etc.) where the ABS_PRESSURE is ignored and only BTN_TOUCH is processed to detect screen taps. Only some special graphics applications read the pressure channel and they will be mixed up by this non-monotonic relation. So we fix it to become: 0 for no pressure (resistance infinite) low value for soft pressure (high resistance) high value for firm pressure (lower resistance) While this patch changes the values reported to userspace, ABS_PRESSURE is used rarely by userspace. Most software only relies on BTN_TOUCH (boolean), which is not affected by this patch. Some graphics software makes use of the interface and does not work correctly with the currently used inverted behaviour. Signed-off-by: H. Nikolaus Schaller Reviewed-By: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 30b53ca95aec..fc7384936011 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -141,6 +141,8 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) "DOWN point(%4d,%4d), resistance (%4u)\n", tc.x, tc.y, rt); + rt = ts->max_rt - rt; + input_report_key(input, BTN_TOUCH, 1); input_report_abs(input, ABS_X, tc.x); input_report_abs(input, ABS_Y, tc.y); -- cgit From 404a24c35db8c44dce91010023f12b73f2f44441 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Feb 2017 23:22:38 -0800 Subject: Input: ad7879 - convert to use regmap Instead of rolling our own infrastructure to provide uniform access to I2C and SPI buses, let's switch to using regmap. Reviewed-by: Michael Hennerich Tested-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 2 + drivers/input/touchscreen/ad7879-i2c.c | 50 ++++----------- drivers/input/touchscreen/ad7879-spi.c | 110 +++++---------------------------- drivers/input/touchscreen/ad7879.c | 46 +++++++++----- drivers/input/touchscreen/ad7879.h | 12 +--- 5 files changed, 64 insertions(+), 156 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 033599777651..574400ba1cb6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -73,6 +73,7 @@ config TOUCHSCREEN_AD7879 config TOUCHSCREEN_AD7879_I2C tristate "support I2C bus connection" depends on TOUCHSCREEN_AD7879 && I2C + select REGMAP_I2C help Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus. @@ -82,6 +83,7 @@ config TOUCHSCREEN_AD7879_I2C config TOUCHSCREEN_AD7879_SPI tristate "support SPI bus connection" depends on TOUCHSCREEN_AD7879 && SPI_MASTER + select REGMAP_SPI help Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus. diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 58f72e0246ab..25aa9b89a6aa 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -12,53 +12,23 @@ #include #include #include +#include #include "ad7879.h" #define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */ -/* All registers are word-sized. - * AD7879 uses a high-byte first convention. - */ -static int ad7879_i2c_read(struct device *dev, u8 reg) -{ - struct i2c_client *client = to_i2c_client(dev); - - return i2c_smbus_read_word_swapped(client, reg); -} - -static int ad7879_i2c_multi_read(struct device *dev, - u8 first_reg, u8 count, u16 *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - u8 idx; - - i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf); - - for (idx = 0; idx < count; ++idx) - buf[idx] = swab16(buf[idx]); - - return 0; -} - -static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val) -{ - struct i2c_client *client = to_i2c_client(dev); - - return i2c_smbus_write_word_swapped(client, reg, val); -} - -static const struct ad7879_bus_ops ad7879_i2c_bus_ops = { - .bustype = BUS_I2C, - .read = ad7879_i2c_read, - .multi_read = ad7879_i2c_multi_read, - .write = ad7879_i2c_write, +static const struct regmap_config ad7879_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 15, }; static int ad7879_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad7879 *ts; + struct regmap *regmap; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -66,8 +36,12 @@ static int ad7879_i2c_probe(struct i2c_client *client, return -EIO; } - ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq, - &ad7879_i2c_bus_ops); + regmap = devm_regmap_init_i2c(client, &ad7879_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ts = ad7879_probe(&client->dev, regmap, client->irq, + BUS_I2C, AD7879_DEVID); if (IS_ERR(ts)) return PTR_ERR(ts); diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index d42b6b9af191..8fb8ccdfac6a 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -11,109 +11,29 @@ #include #include #include +#include #include "ad7879.h" #define AD7879_DEVID 0x7A /* AD7879/AD7889 */ #define MAX_SPI_FREQ_HZ 5000000 -#define AD7879_CMD_MAGIC 0xE000 -#define AD7879_CMD_READ (1 << 10) -#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF)) -#define AD7879_WRITECMD(reg) (AD7879_CMD(reg)) -#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ) -/* - * ad7879_read/write are only used for initial setup and for sysfs controls. - * The main traffic is done in ad7879_collect(). - */ - -static int ad7879_spi_xfer(struct spi_device *spi, - u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf) -{ - struct spi_message msg; - struct spi_transfer *xfers; - void *spi_data; - u16 *command; - u16 *_rx_buf = _rx_buf; /* shut gcc up */ - u8 idx; - int ret; - - xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL); - if (!spi_data) - return -ENOMEM; - - spi_message_init(&msg); - - command = spi_data; - command[0] = cmd; - if (count == 1) { - /* ad7879_spi_{read,write} gave us buf on stack */ - command[1] = *tx_buf; - tx_buf = &command[1]; - _rx_buf = rx_buf; - rx_buf = &command[2]; - } - - ++xfers; - xfers[0].tx_buf = command; - xfers[0].len = 2; - spi_message_add_tail(&xfers[0], &msg); - ++xfers; - - for (idx = 0; idx < count; ++idx) { - if (rx_buf) - xfers[idx].rx_buf = &rx_buf[idx]; - if (tx_buf) - xfers[idx].tx_buf = &tx_buf[idx]; - xfers[idx].len = 2; - spi_message_add_tail(&xfers[idx], &msg); - } +#define AD7879_CMD_MAGIC 0xE0 +#define AD7879_CMD_READ BIT(2) - ret = spi_sync(spi, &msg); - - if (count == 1) - _rx_buf[0] = command[2]; - - kfree(spi_data); - - return ret; -} - -static int ad7879_spi_multi_read(struct device *dev, - u8 first_reg, u8 count, u16 *buf) -{ - struct spi_device *spi = to_spi_device(dev); - - return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf); -} - -static int ad7879_spi_read(struct device *dev, u8 reg) -{ - struct spi_device *spi = to_spi_device(dev); - u16 ret, dummy; - - return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret; -} - -static int ad7879_spi_write(struct device *dev, u8 reg, u16 val) -{ - struct spi_device *spi = to_spi_device(dev); - u16 dummy; - - return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy); -} - -static const struct ad7879_bus_ops ad7879_spi_bus_ops = { - .bustype = BUS_SPI, - .read = ad7879_spi_read, - .multi_read = ad7879_spi_multi_read, - .write = ad7879_spi_write, +static const struct regmap_config ad7879_spi_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 15, + .read_flag_mask = AD7879_CMD_MAGIC | AD7879_CMD_READ, + .write_flag_mask = AD7879_CMD_MAGIC, }; static int ad7879_spi_probe(struct spi_device *spi) { struct ad7879 *ts; + struct regmap *regmap; int err; /* don't exceed max specified SPI CLK frequency */ @@ -125,11 +45,15 @@ static int ad7879_spi_probe(struct spi_device *spi) spi->bits_per_word = 16; err = spi_setup(spi); if (err) { - dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n"); - return err; + dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n"); + return err; } - ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops); + regmap = devm_regmap_init_spi(spi, &ad7879_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ts = ad7879_probe(&spi->dev, regmap, spi->irq, BUS_SPI, AD7879_DEVID); if (IS_ERR(ts)) return PTR_ERR(ts); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index e16a44667da7..6465db7a1b20 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -26,9 +26,8 @@ #include #include #include +#include #include -#include -#include #include #include @@ -106,8 +105,7 @@ enum { #define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50) struct ad7879 { - const struct ad7879_bus_ops *bops; - + struct regmap *regmap; struct device *dev; struct input_dev *input; struct timer_list timer; @@ -137,17 +135,32 @@ struct ad7879 { static int ad7879_read(struct ad7879 *ts, u8 reg) { - return ts->bops->read(ts->dev, reg); -} + unsigned int val; + int error; -static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf) -{ - return ts->bops->multi_read(ts->dev, first_reg, count, buf); + error = regmap_read(ts->regmap, reg, &val); + if (error) { + dev_err(ts->dev, "failed to read register %#02x: %d\n", + reg, error); + return error; + } + + return val; } static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val) { - return ts->bops->write(ts->dev, reg, val); + int error; + + error = regmap_write(ts->regmap, reg, val); + if (error) { + dev_err(ts->dev, + "failed to write %#04x to register %#02x: %d\n", + val, reg, error); + return error; + } + + return 0; } static int ad7879_report(struct ad7879 *ts) @@ -234,7 +247,8 @@ static irqreturn_t ad7879_irq(int irq, void *handle) { struct ad7879 *ts = handle; - ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data); + regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, + ts->conversion_data, AD7879_NR_SENSE); if (!ad7879_report(ts)) mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); @@ -511,8 +525,8 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) return 0; } -struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, - const struct ad7879_bus_ops *bops) +struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid) { struct ad7879_platform_data *pdata = dev_get_platdata(dev); struct ad7879 *ts; @@ -520,7 +534,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, int err; u16 revid; - if (!irq) { + if (irq <= 0) { dev_err(dev, "No IRQ specified\n"); return ERR_PTR(-EINVAL); } @@ -553,10 +567,10 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, return ERR_PTR(-ENOMEM); } - ts->bops = bops; ts->dev = dev; ts->input = input_dev; ts->irq = irq; + ts->regmap = regmap; setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); @@ -564,7 +578,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, input_dev->name = "AD7879 Touchscreen"; input_dev->phys = ts->phys; input_dev->dev.parent = dev; - input_dev->id.bustype = bops->bustype; + input_dev->id.bustype = bustype; input_dev->open = ad7879_open; input_dev->close = ad7879_close; diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h index 6fd13c48d373..1131f8aa118b 100644 --- a/drivers/input/touchscreen/ad7879.h +++ b/drivers/input/touchscreen/ad7879.h @@ -13,18 +13,12 @@ struct ad7879; struct device; - -struct ad7879_bus_ops { - u16 bustype; - int (*read)(struct device *dev, u8 reg); - int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf); - int (*write)(struct device *dev, u8 reg, u16 val); -}; +struct regmap; extern const struct dev_pm_ops ad7879_pm_ops; -struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq, - const struct ad7879_bus_ops *bops); +struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid); void ad7879_remove(struct ad7879 *); #endif -- cgit From 069b2e2cd7ef5b42e1ab8ee991347f9dbf9f51d1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Feb 2017 09:29:40 -0800 Subject: Input: ad7879 - use more devm interfaces gpiochip_add now has a managed version, and we can remove sysfs attribute group via devm_add_action_or_reset (at least until we have devm version of sysfs_create_group). This allows us to get rid of ad7879_remove(). Reviewed-by: Michael Hennerich Tested-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 12 ------- drivers/input/touchscreen/ad7879-spi.c | 10 ------ drivers/input/touchscreen/ad7879.c | 60 ++++++++++++---------------------- drivers/input/touchscreen/ad7879.h | 1 - 4 files changed, 21 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 25aa9b89a6aa..23e04e9f2dad 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -45,17 +45,6 @@ static int ad7879_i2c_probe(struct i2c_client *client, if (IS_ERR(ts)) return PTR_ERR(ts); - i2c_set_clientdata(client, ts); - - return 0; -} - -static int ad7879_i2c_remove(struct i2c_client *client) -{ - struct ad7879 *ts = i2c_get_clientdata(client); - - ad7879_remove(ts); - return 0; } @@ -81,7 +70,6 @@ static struct i2c_driver ad7879_i2c_driver = { .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), }, .probe = ad7879_i2c_probe, - .remove = ad7879_i2c_remove, .id_table = ad7879_id, }; diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 8fb8ccdfac6a..b995891af20d 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -62,15 +62,6 @@ static int ad7879_spi_probe(struct spi_device *spi) return 0; } -static int ad7879_spi_remove(struct spi_device *spi) -{ - struct ad7879 *ts = spi_get_drvdata(spi); - - ad7879_remove(ts); - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id ad7879_spi_dt_ids[] = { { .compatible = "adi,ad7879", }, @@ -86,7 +77,6 @@ static struct spi_driver ad7879_spi_driver = { .of_match_table = of_match_ptr(ad7879_spi_dt_ids), }, .probe = ad7879_spi_probe, - .remove = ad7879_spi_remove, }; module_spi_driver(ad7879_spi_driver); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 6465db7a1b20..b7ab7f9767ca 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -458,7 +458,7 @@ static int ad7879_gpio_add(struct ad7879 *ts, mutex_init(&ts->mutex); - if (pdata->gpio_export) { + if (pdata && pdata->gpio_export) { ts->gc.direction_input = ad7879_gpio_direction_input; ts->gc.direction_output = ad7879_gpio_direction_output; ts->gc.get = ad7879_gpio_get_value; @@ -470,7 +470,7 @@ static int ad7879_gpio_add(struct ad7879 *ts, ts->gc.owner = THIS_MODULE; ts->gc.parent = ts->dev; - ret = gpiochip_add_data(&ts->gc, ts); + ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts); if (ret) dev_err(ts->dev, "failed to register gpio %d\n", ts->gc.base); @@ -478,25 +478,12 @@ static int ad7879_gpio_add(struct ad7879 *ts, return ret; } - -static void ad7879_gpio_remove(struct ad7879 *ts) -{ - const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev); - - if (pdata && pdata->gpio_export) - gpiochip_remove(&ts->gc); - -} #else -static inline int ad7879_gpio_add(struct ad7879 *ts, - const struct ad7879_platform_data *pdata) +static int ad7879_gpio_add(struct ad7879 *ts, + const struct ad7879_platform_data *pdata) { return 0; } - -static inline void ad7879_gpio_remove(struct ad7879 *ts) -{ -} #endif static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) @@ -525,6 +512,13 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) return 0; } +static void ad7879_cleanup_sysfs(void *_ts) +{ + struct ad7879 *ts = _ts; + + sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); +} + struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, int irq, u16 bustype, u8 devid) { @@ -660,36 +654,24 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, err = sysfs_create_group(&dev->kobj, &ad7879_attr_group); if (err) - goto err_out; + return ERR_PTR(err); - if (pdata) { - err = ad7879_gpio_add(ts, pdata); - if (err) - goto err_remove_attr; - } + err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts); + if (err) + return ERR_PTR(err); - err = input_register_device(input_dev); + err = ad7879_gpio_add(ts, pdata); if (err) - goto err_remove_gpio; + return ERR_PTR(err); - return ts; + err = input_register_device(input_dev); + if (err) + return ERR_PTR(err); -err_remove_gpio: - ad7879_gpio_remove(ts); -err_remove_attr: - sysfs_remove_group(&dev->kobj, &ad7879_attr_group); -err_out: - return ERR_PTR(err); + return 0; } EXPORT_SYMBOL(ad7879_probe); -void ad7879_remove(struct ad7879 *ts) -{ - ad7879_gpio_remove(ts); - sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); -} -EXPORT_SYMBOL(ad7879_remove); - MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h index 1131f8aa118b..d3d2e9dc31ae 100644 --- a/drivers/input/touchscreen/ad7879.h +++ b/drivers/input/touchscreen/ad7879.h @@ -19,6 +19,5 @@ extern const struct dev_pm_ops ad7879_pm_ops; struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, int irq, u16 bustype, u8 devid); -void ad7879_remove(struct ad7879 *); #endif -- cgit From b621e30be6120f1b20c6077a3462dd261d6ecc90 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Feb 2017 10:45:59 -0800 Subject: Input: ad7879 - allow exporting AUX/VBAT/GPIO pin via device property Up until now only platforms using legacy platform data were able to switch AUX/VBAT/GPIO pin in GPIO mode and use it as regular GPIO line. Let's allow platforms using generic device properties to do the same. Reviewed-by: Michael Hennerich Tested-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index b7ab7f9767ca..b6da5cee80eb 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -454,17 +454,28 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip, static int ad7879_gpio_add(struct ad7879 *ts, const struct ad7879_platform_data *pdata) { + bool gpio_export; + int gpio_base; int ret = 0; + if (pdata) { + gpio_export = pdata->gpio_export; + gpio_base = pdata->gpio_base; + } else { + gpio_export = device_property_read_bool(ts->dev, + "gpio-controller"); + gpio_base = -1; + } + mutex_init(&ts->mutex); - if (pdata && pdata->gpio_export) { + if (gpio_export) { ts->gc.direction_input = ad7879_gpio_direction_input; ts->gc.direction_output = ad7879_gpio_direction_output; ts->gc.get = ad7879_gpio_get_value; ts->gc.set = ad7879_gpio_set_value; ts->gc.can_sleep = 1; - ts->gc.base = pdata->gpio_base; + ts->gc.base = gpio_base; ts->gc.ngpio = 1; ts->gc.label = "AD7879-GPIO"; ts->gc.owner = THIS_MODULE; -- cgit From b4816f794d672494deb6e87bb0a8ef41ca1ca329 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 22 Feb 2017 10:32:48 -0800 Subject: Input: ad7879-spi - remove bits_per_word = 16 enforcement Using regmap this is no longer required. Signed-off-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-spi.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index b995891af20d..7af5a2349173 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -34,7 +34,6 @@ static int ad7879_spi_probe(struct spi_device *spi) { struct ad7879 *ts; struct regmap *regmap; - int err; /* don't exceed max specified SPI CLK frequency */ if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { @@ -42,13 +41,6 @@ static int ad7879_spi_probe(struct spi_device *spi) return -EINVAL; } - spi->bits_per_word = 16; - err = spi_setup(spi); - if (err) { - dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n"); - return err; - } - regmap = devm_regmap_init_spi(spi, &ad7879_spi_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); -- cgit From 2581e5d104298fc72022a6f849921533693d08fe Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 22 Feb 2017 10:34:20 -0800 Subject: Input: ad7879 - update MODULE_AUTHOR email address Signed-off-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 2 +- drivers/input/touchscreen/ad7879-spi.c | 2 +- drivers/input/touchscreen/ad7879.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 23e04e9f2dad..a282d1c9e2c6 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -75,6 +75,6 @@ static struct i2c_driver ad7879_i2c_driver = { module_i2c_driver(ad7879_i2c_driver); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 7af5a2349173..c73798297b98 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -73,7 +73,7 @@ static struct spi_driver ad7879_spi_driver = { module_spi_driver(ad7879_spi_driver); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:ad7879"); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index b6da5cee80eb..53ab689305ac 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -683,6 +683,6 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, } EXPORT_SYMBOL(ad7879_probe); -MODULE_AUTHOR("Michael Hennerich "); +MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver"); MODULE_LICENSE("GPL"); -- cgit From 9dd46c02532a6bed6240101ecf4bbc407f8c6adf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 13 Feb 2017 15:45:59 -0800 Subject: Input: tca8418_keypad - remove double read of key event register There is no need to tread the same register twice in a row. Fixes: ea4348c8462a ("Input: tca8418_keypad - hide gcc-4.9 -Wmaybe-un ...") Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca8418_keypad.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 44dd7689c571..e37e335e406f 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -188,8 +188,6 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) input_event(input, EV_MSC, MSC_SCAN, code); input_report_key(input, keymap[code], state); - /* Read for next loop */ - error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); } while (1); input_sync(input); -- cgit From a4deb14712bdd0bd261de38be1d9f01f5b26543d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 25 Feb 2017 10:32:58 -0800 Subject: Input: ad7879 - add header file to fix ad7879.c build errors Add header file to fix these build errors: ../drivers/input/touchscreen/ad7879.c: In function 'ad7879_parse_dt': ../drivers/input/touchscreen/ad7879.c:505:2: error: implicit declaration of function 'device_property_read_u32' [-Werror=implicit-function-declaration] err = device_property_read_u32(dev, "adi,resistance-plate-x", &tmp); ^ ../drivers/input/touchscreen/ad7879.c:512:2: error: implicit declaration of function 'device_property_read_u8' [-Werror=implicit-function-declaration] device_property_read_u8(dev, "adi,first-conversion-delay", ^ ../drivers/input/touchscreen/ad7879.c:521:2: error: implicit declaration of function 'device_property_read_bool' [-Werror=implicit-function-declaration] ts->swap_xy = device_property_read_bool(dev, "touchscreen-swapped-x-y"); ^ Signed-off-by: Randy Dunlap Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 53ab689305ac..1bd870277e1a 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include -- cgit From af160c542e40c133b12b18d9dddd4fc555611ef1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 28 Feb 2017 13:57:21 -0800 Subject: Input: ad7879 - make sure we set up drvdata The conversion to devm accidentally removed setting up of I2C client data upon successful probe of the touchscreen. Let's move this setting into the core, so we do not forger about it again. Fixes: 381f688eee3d ("Input: ad7879 - use more devm interfaces") Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-spi.c | 2 -- drivers/input/touchscreen/ad7879.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index c73798297b98..59486ccba37d 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -49,8 +49,6 @@ static int ad7879_spi_probe(struct spi_device *spi) if (IS_ERR(ts)) return PTR_ERR(ts); - spi_set_drvdata(spi, ts); - return 0; } diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 1bd870277e1a..52daaa4edc67 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -680,6 +680,8 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, if (err) return ERR_PTR(err); + dev_set_drvdata(dev, ts); + return 0; } EXPORT_SYMBOL(ad7879_probe); -- cgit From 4e34025b340174e220646d82a3e81641fc02f42b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 28 Feb 2017 11:43:52 -0800 Subject: Input: ad7879 - return plain error code from ad7879_probe() With the switch to devm, there is no need for ad7879_probe() to return the touchscreen structure, we can use plain error code. This also fixes issue introduced with devm concersion, where we returned 0 on success (which worked OK since IS_ERR(0) would not trigger, but was not correct regardless). Fixes: 381f688eee3d ("Input: ad7879 - use more devm interfaces") Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879-i2c.c | 9 ++------- drivers/input/touchscreen/ad7879-spi.c | 7 +------ drivers/input/touchscreen/ad7879.c | 28 ++++++++++++++-------------- drivers/input/touchscreen/ad7879.h | 5 ++--- 4 files changed, 19 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index a282d1c9e2c6..49b902b10c5f 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -27,7 +27,6 @@ static const struct regmap_config ad7879_i2c_regmap_config = { static int ad7879_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct ad7879 *ts; struct regmap *regmap; if (!i2c_check_functionality(client->adapter, @@ -40,12 +39,8 @@ static int ad7879_i2c_probe(struct i2c_client *client, if (IS_ERR(regmap)) return PTR_ERR(regmap); - ts = ad7879_probe(&client->dev, regmap, client->irq, - BUS_I2C, AD7879_DEVID); - if (IS_ERR(ts)) - return PTR_ERR(ts); - - return 0; + return ad7879_probe(&client->dev, regmap, client->irq, + BUS_I2C, AD7879_DEVID); } static const struct i2c_device_id ad7879_id[] = { diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index 59486ccba37d..3457a5626d75 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -32,7 +32,6 @@ static const struct regmap_config ad7879_spi_regmap_config = { static int ad7879_spi_probe(struct spi_device *spi) { - struct ad7879 *ts; struct regmap *regmap; /* don't exceed max specified SPI CLK frequency */ @@ -45,11 +44,7 @@ static int ad7879_spi_probe(struct spi_device *spi) if (IS_ERR(regmap)) return PTR_ERR(regmap); - ts = ad7879_probe(&spi->dev, regmap, spi->irq, BUS_SPI, AD7879_DEVID); - if (IS_ERR(ts)) - return PTR_ERR(ts); - - return 0; + return ad7879_probe(&spi->dev, regmap, spi->irq, BUS_SPI, AD7879_DEVID); } #ifdef CONFIG_OF diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 52daaa4edc67..7118f611e222 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -531,8 +531,8 @@ static void ad7879_cleanup_sysfs(void *_ts) sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); } -struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, - int irq, u16 bustype, u8 devid) +int ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid) { struct ad7879_platform_data *pdata = dev_get_platdata(dev); struct ad7879 *ts; @@ -542,12 +542,12 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, if (irq <= 0) { dev_err(dev, "No IRQ specified\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); if (!ts) - return ERR_PTR(-ENOMEM); + return -ENOMEM; if (pdata) { /* Platform data use swapped axis (backward compatibility) */ @@ -564,13 +564,13 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, ad7879_parse_dt(dev, ts); } else { dev_err(dev, "No platform data\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } input_dev = devm_input_allocate_device(dev); if (!input_dev) { dev_err(dev, "Failed to allocate input device\n"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } ts->dev = dev; @@ -618,14 +618,14 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, touchscreen_parse_properties(input_dev, false, NULL); if (!input_abs_get_max(input_dev, ABS_PRESSURE)) { dev_err(dev, "Touchscreen pressure is not specified\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } } err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET); if (err < 0) { dev_err(dev, "Failed to write %s\n", input_dev->name); - return ERR_PTR(err); + return err; } revid = ad7879_read(ts, AD7879_REG_REVID); @@ -634,7 +634,7 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, if (input_dev->id.product != devid) { dev_err(dev, "Failed to probe %s (%x vs %x)\n", input_dev->name, devid, revid); - return ERR_PTR(-ENODEV); + return -ENODEV; } ts->cmd_crtl3 = AD7879_YPLUS_BIT | @@ -659,26 +659,26 @@ struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, dev_name(dev), ts); if (err) { dev_err(dev, "Failed to request IRQ: %d\n", err); - return ERR_PTR(err); + return err; } __ad7879_disable(ts); err = sysfs_create_group(&dev->kobj, &ad7879_attr_group); if (err) - return ERR_PTR(err); + return err; err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts); if (err) - return ERR_PTR(err); + return err; err = ad7879_gpio_add(ts, pdata); if (err) - return ERR_PTR(err); + return err; err = input_register_device(input_dev); if (err) - return ERR_PTR(err); + return err; dev_set_drvdata(dev, ts); diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h index d3d2e9dc31ae..7e43066a4b68 100644 --- a/drivers/input/touchscreen/ad7879.h +++ b/drivers/input/touchscreen/ad7879.h @@ -11,13 +11,12 @@ #include -struct ad7879; struct device; struct regmap; extern const struct dev_pm_ops ad7879_pm_ops; -struct ad7879 *ad7879_probe(struct device *dev, struct regmap *regmap, - int irq, u16 bustype, u8 devid); +int ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid); #endif -- cgit From 3a97c3d16b9e087a1741c527ecd8cbb4039d609f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 28 Feb 2017 11:50:56 -0800 Subject: Input: ad7879 - try parsing properties on non-DT systems We have switched the driver to use generic device properties API, so there is no need to check for presence of DT node before trying parse properties. Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index 7118f611e222..c415614ada68 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -560,11 +560,10 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, ts->averaging = pdata->averaging; ts->pen_down_acc_interval = pdata->pen_down_acc_interval; ts->median = pdata->median; - } else if (dev->of_node) { - ad7879_parse_dt(dev, ts); } else { - dev_err(dev, "No platform data\n"); - return -EINVAL; + err = ad7879_parse_dt(dev, ts); + if (err) + return err; } input_dev = devm_input_allocate_device(dev); -- cgit From 4f95963558d4ed0019938b5410a3402700a1bc4c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 28 Feb 2017 11:56:20 -0800 Subject: Input: ad7879 - do not manipulate capability bits directly Instead of manipulating capabilities bits of input device directly, let's use input_set_capability() API. Also, stop setting ABS_X/Y bits explicitly as input_set_abs_params() does this for us. Acked-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ad7879.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index c415614ada68..196028c45210 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -590,13 +590,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, input_set_drvdata(input_dev, ts); - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(ABS_X, input_dev->absbit); - __set_bit(ABS_Y, input_dev->absbit); - __set_bit(ABS_PRESSURE, input_dev->absbit); - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(BTN_TOUCH, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); if (pdata) { input_set_abs_params(input_dev, ABS_X, @@ -614,6 +608,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap, } else { input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); + input_set_capability(input_dev, EV_ABS, ABS_PRESSURE); touchscreen_parse_properties(input_dev, false, NULL); if (!input_abs_get_max(input_dev, ABS_PRESSURE)) { dev_err(dev, "Touchscreen pressure is not specified\n"); -- cgit From 09c398bc01f507e31b9c1325a10e231d271fea00 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:41:34 -0800 Subject: Input: alps - move ALPS_PROTO_V4 out of alps_model_data table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like for other protocols create alps_v4_protocol_data and use it in alps_identify() function. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 72b28ebfe360..f36de829390b 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -138,7 +138,6 @@ static const struct alps_model_info alps_model_data[] = { { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ - { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } }, }; static const struct alps_protocol_info alps_v3_protocol_data = { @@ -149,6 +148,10 @@ static const struct alps_protocol_info alps_v3_rushmore_data = { ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT }; +static const struct alps_protocol_info alps_v4_protocol_data = { + ALPS_PROTO_V4, 0x8f, 0x8f, 0 +}; + static const struct alps_protocol_info alps_v5_protocol_data = { ALPS_PROTO_V5, 0xc8, 0xd8, 0 }; @@ -2815,7 +2818,10 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) protocol = alps_match_table(e7, ec); if (!protocol) { - if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && + if (e7[0] == 0x73 && e7[1] == 0x02 && e7[2] == 0x64 && + ec[2] == 0x8a) { + protocol = &alps_v4_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { protocol = &alps_v5_protocol_data; } else if (ec[0] == 0x88 && -- cgit From c9815232c3cca58bb2b664f37b681841981ed4a9 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:42:46 -0800 Subject: Input: alps - warn about unsupported ALPS V9 touchpad MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for devices with ALPS_PROTO_V9 is not implemented yet but we can detect these alps touchpads and warn users about it. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 10 ++++++++++ drivers/input/mouse/alps.h | 1 + 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f36de829390b..c893af6a33b0 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -164,6 +164,10 @@ static const struct alps_protocol_info alps_v8_protocol_data = { ALPS_PROTO_V8, 0x18, 0x18, 0 }; +static const struct alps_protocol_info alps_v9_protocol_data = { + ALPS_PROTO_V9, 0xc8, 0xc8, 0 +}; + /* * Some v2 models report the stick buttons in separate bits */ @@ -2838,6 +2842,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x28 && ec[1] == 0x01) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) { + protocol = &alps_v9_protocol_data; + psmouse_warn(psmouse, + "Unsupported ALPS V9 touchpad: E7=%3ph, EC=%3ph\n", + e7, ec); + return -EINVAL; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 6d279aa27cb9..54f9f4401a77 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -23,6 +23,7 @@ #define ALPS_PROTO_V6 0x600 #define ALPS_PROTO_V7 0x700 /* t3btl t4s */ #define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ +#define ALPS_PROTO_V9 0x900 /* ss3btl */ #define MAX_TOUCHES 4 -- cgit From a3cbfd56ff909393e2d59236d94205ae17dfc5d5 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 7 Mar 2017 09:43:35 -0800 Subject: Input: alps - cleanup alps_model_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort all devices in alps_model_data by signature and remove command_mode_resp which is not used anymore. Signed-off-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 56 +++++++++++++++++++++------------------------- drivers/input/mouse/alps.h | 5 ----- 2 files changed, 25 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index c893af6a33b0..e761955978c6 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -106,38 +106,36 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ - { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ - { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ - { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ - { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ - /* * XXX This entry is suspicious. First byte has zero lower nibble, * which is what a normal mouse would report. Also, the value 0x0e * isn't valid per PS/2 spec. */ - { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - - { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ - { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, - { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ - { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ - { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, + { { 0x20, 0x02, 0x0e }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + + { { 0x22, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + { { 0x22, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ + { { 0x32, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ + { { 0x33, 0x02, 0x0a }, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ + { { 0x52, 0x01, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ + { { 0x53, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x53, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x60, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ + { { 0x62, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x63, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x28 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x64 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ + { { 0x73, 0x00, 0x14 }, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ + { { 0x73, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x73, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ }; static const struct alps_protocol_info alps_v3_protocol_data = { @@ -2779,12 +2777,8 @@ static const struct alps_protocol_info *alps_match_table(unsigned char *e7, for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { model = &alps_model_data[i]; - if (!memcmp(e7, model->signature, sizeof(model->signature)) && - (!model->command_mode_resp || - model->command_mode_resp == ec[2])) { - + if (!memcmp(e7, model->signature, sizeof(model->signature))) return &model->protocol_info; - } } return NULL; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 54f9f4401a77..dea31638c91f 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -163,10 +163,6 @@ struct alps_protocol_info { /** * struct alps_model_info - touchpad ID table * @signature: E7 response string to match. - * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response - * (aka command mode response) identifies the firmware minor version. This - * can be used to distinguish different hardware models which are not - * uniquely identifiable through their E7 responses. * @protocol_info: information about protocol used by the device. * * Many (but not all) ALPS touchpads can be identified by looking at the @@ -175,7 +171,6 @@ struct alps_protocol_info { */ struct alps_model_info { u8 signature[3]; - u8 command_mode_resp; struct alps_protocol_info protocol_info; }; -- cgit From fad358a06c51bd40a131f4f94711c46e5d77cdae Mon Sep 17 00:00:00 2001 From: Guan Ben Date: Tue, 7 Mar 2017 10:25:27 -0800 Subject: Input: pwm-beeper - support customized freq for SND_BELL Extend the pwm-beeper driver to support customized frequency for SND_BELL from device properties. Signed-off-by: Guan Ben Signed-off-by: Mark Jonas Signed-off-by: Heiko Schocher Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pwm-beeper.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index e53801dbd560..edca0d737750 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ struct pwm_beeper { struct regulator *amplifier; struct work_struct work; unsigned long period; + unsigned int bell_frequency; bool suspended; bool amplifier_on; }; @@ -94,7 +96,7 @@ static int pwm_beeper_event(struct input_dev *input, switch (code) { case SND_BELL: - value = value ? 1000 : 0; + value = value ? beeper->bell_frequency : 0; break; case SND_TONE: break; @@ -131,6 +133,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pwm_beeper *beeper; struct pwm_state state; + u32 bell_frequency; int error; beeper = devm_kzalloc(dev, sizeof(*beeper), GFP_KERNEL); @@ -167,6 +170,16 @@ static int pwm_beeper_probe(struct platform_device *pdev) INIT_WORK(&beeper->work, pwm_beeper_work); + error = device_property_read_u32(dev, "beeper-hz", &bell_frequency); + if (error) { + bell_frequency = 1000; + dev_dbg(dev, + "failed to parse 'beeper-hz' property, using default: %uHz\n", + bell_frequency); + } + + beeper->bell_frequency = bell_frequency; + beeper->input = devm_input_allocate_device(dev); if (!beeper->input) { dev_err(dev, "Failed to allocate input device\n"); -- cgit From fabeb165afd52a3fb05b9b68e5a3550609b8e157 Mon Sep 17 00:00:00 2001 From: MichaÅ‚ KÄ™pieÅ„ Date: Wed, 8 Mar 2017 09:20:10 -0800 Subject: Input: sparse-keymap - use a managed allocation for keymap copy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some platform drivers use devm_input_allocate_device() together with sparse_keymap_setup() in their .probe callbacks. While using the former simplifies error handling, using the latter necessitates calling sparse_keymap_free() in the error path and upon module unloading to avoid leaking the copy of the keymap allocated by sparse_keymap_setup(). To help prevent such leaks and enable simpler error handling, make sparse_keymap_setup() use devm_kmemdup() to create the keymap copy so that it gets automatically freed. This works for both managed and non-managed input devices as the keymap is freed after the last reference to the input device is dropped. Note that actions previously taken by sparse_keymap_free(), i.e. taking the input device's mutex and zeroing its keycode and keycodemax fields, are now redundant because the managed keymap will always be freed after the input device is unregistered. Signed-off-by: MichaÅ‚ KÄ™pieÅ„ Signed-off-by: Dmitry Torokhov --- drivers/input/sparse-keymap.c | 39 +++++++++------------------------------ 1 file changed, 9 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index e7409c45bdd0..12a3ad83296d 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -160,12 +160,12 @@ static int sparse_keymap_setkeycode(struct input_dev *dev, * @keymap: Keymap in form of array of &key_entry structures ending * with %KE_END type entry * @setup: Function that can be used to adjust keymap entries - * depending on device's deeds, may be %NULL + * depending on device's needs, may be %NULL * * The function calculates size and allocates copy of the original * keymap after which sets up input device event bits appropriately. - * Before destroying input device allocated keymap should be freed - * with a call to sparse_keymap_free(). + * The allocated copy of the keymap is automatically freed when it + * is no longer needed. */ int sparse_keymap_setup(struct input_dev *dev, const struct key_entry *keymap, @@ -180,19 +180,18 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL); + map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), + GFP_KERNEL); if (!map) return -ENOMEM; - memcpy(map, keymap, map_size * sizeof(struct key_entry)); - for (i = 0; i < map_size; i++) { entry = &map[i]; if (setup) { error = setup(dev, entry); if (error) - goto err_out; + return error; } switch (entry->type) { @@ -221,10 +220,6 @@ int sparse_keymap_setup(struct input_dev *dev, dev->setkeycode = sparse_keymap_setkeycode; return 0; - - err_out: - kfree(map); - return error; } EXPORT_SYMBOL(sparse_keymap_setup); @@ -232,29 +227,13 @@ EXPORT_SYMBOL(sparse_keymap_setup); * sparse_keymap_free - free memory allocated for sparse keymap * @dev: Input device using sparse keymap * - * This function is used to free memory allocated by sparse keymap + * This function used to free memory allocated by sparse keymap * in an input device that was set up by sparse_keymap_setup(). - * NOTE: It is safe to cal this function while input device is - * still registered (however the drivers should care not to try to - * use freed keymap and thus have to shut off interrupts/polling - * before freeing the keymap). + * Since sparse_keymap_setup() now uses a managed allocation for the + * keymap copy, use of this function is deprecated. */ void sparse_keymap_free(struct input_dev *dev) { - unsigned long flags; - - /* - * Take event lock to prevent racing with input_get_keycode() - * and input_set_keycode() if we are called while input device - * is still registered. - */ - spin_lock_irqsave(&dev->event_lock, flags); - - kfree(dev->keycode); - dev->keycode = NULL; - dev->keycodemax = 0; - - spin_unlock_irqrestore(&dev->event_lock, flags); } EXPORT_SYMBOL(sparse_keymap_free); -- cgit From bc682a50a0716f556cf6dfb209bd8d772c1d635c Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Thu, 9 Mar 2017 09:46:17 -0800 Subject: Input: drv260x - remove OF dependency As the driver is using generic device properties, it should work properly when CONFIG_OF is turned off. This patch removes the ifdef CONFIGOF and make sure the driver always have of_match_table. Signed-off-by: Jingkui Wang Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index fb089d36c0d6..17eb84ab4c0b 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -652,7 +652,6 @@ static const struct i2c_device_id drv260x_id[] = { }; MODULE_DEVICE_TABLE(i2c, drv260x_id); -#ifdef CONFIG_OF static const struct of_device_id drv260x_of_match[] = { { .compatible = "ti,drv2604", }, { .compatible = "ti,drv2604l", }, @@ -661,13 +660,12 @@ static const struct of_device_id drv260x_of_match[] = { { } }; MODULE_DEVICE_TABLE(of, drv260x_of_match); -#endif static struct i2c_driver drv260x_driver = { .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", - .of_match_table = of_match_ptr(drv260x_of_match), + .of_match_table = drv260x_of_match, .pm = &drv260x_pm_ops, }, .id_table = drv260x_id, -- cgit From 73915f369e6957c0d7ddca9f7435cc6f76d5320a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Mar 2017 09:47:01 -0800 Subject: Input: axp20x-pek - use our own device for errors Before this commit axp20x-pek was mixing 2 style error reporting calls: dev_err(&pdev->dev, ...); dev_err(axp20x->dev, ...); But the second is our parent device, not our own device, so switch to using &pdev->dev everywhere. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 1ac898db303a..a041365b1868 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -239,7 +239,7 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek_irq, 0, "axp20x-pek-dbr", idev); if (error < 0) { - dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", + dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", axp20x_pek->irq_dbr, error); return error; } @@ -248,14 +248,14 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek_irq, 0, "axp20x-pek-dbf", idev); if (error < 0) { - dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n", + dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", axp20x_pek->irq_dbf, error); return error; } error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); if (error) { - dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n", + dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n", error); return error; } @@ -271,7 +271,7 @@ static int axp20x_pek_probe(struct platform_device *pdev) error = input_register_device(idev); if (error) { - dev_err(axp20x->dev, "Can't register input device: %d\n", + dev_err(&pdev->dev, "Can't register input device: %d\n", error); return error; } -- cgit From f2bd5a9ec5edc307e5f84dc9df14253898e19678 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Mar 2017 09:47:24 -0800 Subject: Input: axp20x_pek - add axp20x_pek_probe_input_device helper Move all input device related initialization into a new axp20x_pek_probe_input_device helper function. This introduces one functional change, the input device is now registered before the sysfs attr get registered. This is not a problem as the sysfs attr are to configure some long press settings (forced poweroff) in the hardware and do not interact with the input_device. This is a preparation patch for not always registering the input dev. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 47 +++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index a041365b1868..b7258ecd5a17 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -188,21 +188,13 @@ static void axp20x_remove_sysfs_group(void *_data) sysfs_remove_group(&dev->kobj, &axp20x_attribute_group); } -static int axp20x_pek_probe(struct platform_device *pdev) +static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, + struct platform_device *pdev) { - struct axp20x_pek *axp20x_pek; - struct axp20x_dev *axp20x; + struct axp20x_dev *axp20x = axp20x_pek->axp20x; struct input_dev *idev; int error; - axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), - GFP_KERNEL); - if (!axp20x_pek) - return -ENOMEM; - - axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); - axp20x = axp20x_pek->axp20x; - axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); if (axp20x_pek->irq_dbr < 0) { dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n", @@ -253,6 +245,32 @@ static int axp20x_pek_probe(struct platform_device *pdev) return error; } + error = input_register_device(idev); + if (error) { + dev_err(&pdev->dev, "Can't register input device: %d\n", + error); + return error; + } + + return 0; +} + +static int axp20x_pek_probe(struct platform_device *pdev) +{ + struct axp20x_pek *axp20x_pek; + int error; + + axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), + GFP_KERNEL); + if (!axp20x_pek) + return -ENOMEM; + + axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); + + error = axp20x_pek_probe_input_device(axp20x_pek, pdev); + if (error) + return error; + error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); if (error) { dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n", @@ -269,13 +287,6 @@ static int axp20x_pek_probe(struct platform_device *pdev) return error; } - error = input_register_device(idev); - if (error) { - dev_err(&pdev->dev, "Can't register input device: %d\n", - error); - return error; - } - platform_set_drvdata(pdev, axp20x_pek); return 0; -- cgit From 9b13a4ca8d2c44ca659d8df65f15c48c2e9b9316 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Mar 2017 09:55:49 -0800 Subject: Input: axp20x-pek - do not register input device on some systems On some systems (Intel tablets with axp288 pmic) the powerbutton is also connected to a gpio pin of the SoC, advertised through the "INTCFD9" / "PNP0C40" acpi device. This leads to double reporting of powerbutton events, which is undesirable, so one driver needs to not report input events in this case. Since the soc_button_array driver for the "PNP0C40" acpi device also handles wake from suspend on these tablets and since the axp20x-pel driver requires relative expensive i2c accrsses, it is best for the axp20x-pek driver to not register an input device in this case. Note that this commit leaves the axp20x-driver bound to the device, rather then returning -ENODEV, this is done so that the sysfs attributes it offers are kept around. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/axp20x-pek.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index b7258ecd5a17..f11807db6979 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -267,9 +268,17 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); - error = axp20x_pek_probe_input_device(axp20x_pek, pdev); - if (error) - return error; + /* + * Do not register the input device if there is an "INTCFD9" + * gpio button ACPI device, that handles the power button too, + * and otherwise we end up reporting all presses twice. + */ + if (!acpi_dev_found("INTCFD9") || + !IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY)) { + error = axp20x_pek_probe_input_device(axp20x_pek, pdev); + if (error) + return error; + } error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); if (error) { -- cgit From a01cd17000a4eb35060666f181f1d46832b59030 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Mar 2017 09:58:30 -0800 Subject: Input: soc_button_array - use NULL for GPIO connection ID The gpiolib-acpi code is becoming more strict and connection-IDs may only be used with devices which have a _DSD with matching IDs in there. Since the soc_button_array ACPI binding is pure index based pass in NULL as connection-ID to avoid the more strict cheks resulting in gpiod_count and gpiod_get_index not returning any gpios. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index ddb2f22fca7a..0cd2cac47660 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -55,7 +55,7 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index) struct gpio_desc *desc; int gpio; - desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS); + desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -169,7 +169,7 @@ static int soc_button_probe(struct platform_device *pdev) button_info = (struct soc_button_info *)id->driver_data; - if (gpiod_count(dev, KBUILD_MODNAME) <= 0) { + if (gpiod_count(dev, NULL) <= 0) { dev_dbg(dev, "no GPIO attached, ignoring...\n"); return -ENODEV; } -- cgit From a227954756de74d8e70d70135e405d69dea4e3fe Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 8 Mar 2017 09:21:13 -0800 Subject: Input: dm355evm_keys - remove use of sparse_keymap_free Now that sparse keymap uses managed memory, we no longer need to clean it up manually. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/dm355evm_keys.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 82e272ebc0ed..5db493dfe509 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -213,21 +213,19 @@ static int dm355evm_keys_probe(struct platform_device *pdev) IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name(&pdev->dev), keys); if (status < 0) - goto fail2; + goto fail1; /* register */ status = input_register_device(input); if (status < 0) - goto fail3; + goto fail2; platform_set_drvdata(pdev, keys); return 0; -fail3: - free_irq(keys->irq, keys); fail2: - sparse_keymap_free(input); + free_irq(keys->irq, keys); fail1: input_free_device(input); kfree(keys); @@ -241,7 +239,6 @@ static int dm355evm_keys_remove(struct platform_device *pdev) struct dm355evm_keys *keys = platform_get_drvdata(pdev); free_irq(keys->irq, keys); - sparse_keymap_free(keys->input); input_unregister_device(keys->input); kfree(keys); -- cgit From fc2a6e5048c6812253590b8ae26eed3236b25eac Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 8 Mar 2017 09:27:27 -0800 Subject: Input: wistron_btns - remove use of sparse_keymap_free Now that sparse keymap uses managed memory, we no longer need to clean it up manually. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index e25f87ba19f6..43e67f546366 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1243,12 +1243,10 @@ static int setup_input_dev(void) error = input_register_polled_device(wistron_idev); if (error) - goto err_free_keymap; + goto err_free_dev; return 0; - err_free_keymap: - sparse_keymap_free(input_dev); err_free_dev: input_free_polled_device(wistron_idev); return error; @@ -1300,7 +1298,6 @@ static int wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_polled_device(wistron_idev); - sparse_keymap_free(wistron_idev->input); input_free_polled_device(wistron_idev); bios_detach(); -- cgit From 52e4f1d601daaee0bad6b22765befc21b180d701 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 8 Mar 2017 09:36:23 -0800 Subject: Input: dm355evm_keys - switch to using managed resources Using devm_* APIs simpifies error handling and device teardown. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/dm355evm_keys.c | 76 +++++++++++++------------------------- 1 file changed, 26 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 5db493dfe509..bab256ef32b9 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -32,7 +32,6 @@ struct dm355evm_keys { struct input_dev *input; struct device *dev; - int irq; }; /* These initial keycodes can be remapped */ @@ -176,71 +175,49 @@ static int dm355evm_keys_probe(struct platform_device *pdev) { struct dm355evm_keys *keys; struct input_dev *input; - int status; + int irq; + int error; - /* allocate instance struct and input dev */ - keys = kzalloc(sizeof *keys, GFP_KERNEL); - input = input_allocate_device(); - if (!keys || !input) { - status = -ENOMEM; - goto fail1; - } + keys = devm_kzalloc(&pdev->dev, sizeof (*keys), GFP_KERNEL); + if (!keys) + return -ENOMEM; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; keys->dev = &pdev->dev; keys->input = input; - /* set up "threaded IRQ handler" */ - status = platform_get_irq(pdev, 0); - if (status < 0) - goto fail1; - keys->irq = status; - input->name = "DM355 EVM Controls"; input->phys = "dm355evm/input0"; - input->dev.parent = &pdev->dev; input->id.bustype = BUS_I2C; input->id.product = 0x0355; input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); - status = sparse_keymap_setup(input, dm355evm_keys, NULL); - if (status) - goto fail1; + error = sparse_keymap_setup(input, dm355evm_keys, NULL); + if (error) + return error; /* REVISIT: flush the event queue? */ - status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&pdev->dev), keys); - if (status < 0) - goto fail1; - - /* register */ - status = input_register_device(input); - if (status < 0) - goto fail2; - - platform_set_drvdata(pdev, keys); - - return 0; - -fail2: - free_irq(keys->irq, keys); -fail1: - input_free_device(input); - kfree(keys); - dev_err(&pdev->dev, "can't register, err %d\n", status); - - return status; -} + /* set up "threaded IRQ handler" */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; -static int dm355evm_keys_remove(struct platform_device *pdev) -{ - struct dm355evm_keys *keys = platform_get_drvdata(pdev); + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, dm355evm_keys_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&pdev->dev), keys); + if (error) + return error; - free_irq(keys->irq, keys); - input_unregister_device(keys->input); - kfree(keys); + /* register */ + error = input_register_device(input); + if (error) + return error; return 0; } @@ -256,7 +233,6 @@ static int dm355evm_keys_remove(struct platform_device *pdev) */ static struct platform_driver dm355evm_keys_driver = { .probe = dm355evm_keys_probe, - .remove = dm355evm_keys_remove, .driver = { .name = "dm355evm_keys", }, -- cgit From 2e2a0db8c88d47123d3dd29d46eba12c26f71149 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Fri, 10 Mar 2017 16:26:08 -0800 Subject: Input: tps6507x-ts - update to devm_* API Update the code to use devm_* API so that driver core will manage resources. Signed-off-by: Yegor Yefremov Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tps6507x-ts.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index a340bfccdfb6..75170a7439b1 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -226,7 +226,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev) */ init_data = tps_board->tps6507x_ts_init_data; - tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); + tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL); if (!tsc) { dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); return -ENOMEM; @@ -240,11 +240,10 @@ static int tps6507x_ts_probe(struct platform_device *pdev) snprintf(tsc->phys, sizeof(tsc->phys), "%s/input0", dev_name(tsc->dev)); - poll_dev = input_allocate_polled_device(); + poll_dev = devm_input_allocate_polled_device(&pdev->dev); if (!poll_dev) { dev_err(tsc->dev, "Failed to allocate polled input device.\n"); - error = -ENOMEM; - goto err_free_mem; + return -ENOMEM; } tsc->poll_dev = poll_dev; @@ -274,32 +273,11 @@ static int tps6507x_ts_probe(struct platform_device *pdev) error = tps6507x_adc_standby(tsc); if (error) - goto err_free_polled_dev; + return error; error = input_register_polled_device(poll_dev); if (error) - goto err_free_polled_dev; - - platform_set_drvdata(pdev, tsc); - - return 0; - -err_free_polled_dev: - input_free_polled_device(poll_dev); -err_free_mem: - kfree(tsc); - return error; -} - -static int tps6507x_ts_remove(struct platform_device *pdev) -{ - struct tps6507x_ts *tsc = platform_get_drvdata(pdev); - struct input_polled_dev *poll_dev = tsc->poll_dev; - - input_unregister_polled_device(poll_dev); - input_free_polled_device(poll_dev); - - kfree(tsc); + return error; return 0; } @@ -309,7 +287,6 @@ static struct platform_driver tps6507x_ts_driver = { .name = "tps6507x-ts", }, .probe = tps6507x_ts_probe, - .remove = tps6507x_ts_remove, }; module_platform_driver(tps6507x_ts_driver); -- cgit From 7283b47d5d4d8e6528a08dc6c7ac6ff7cfed66d9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Mar 2017 14:03:28 -0700 Subject: Input: soc_button_array - get rid of MAX_NBUTTONS Count how much gpio_keys we actually need, this is a preparation patch for adding support for the new Win10 / ACPI-6.0 "Generic Buttons Device" support. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index 0cd2cac47660..b8769f6e3601 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -20,13 +20,6 @@ #include #include -/* - * Definition of buttons on the tablet. The ACPI index of each button - * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC - * Platforms" - */ -#define MAX_NBUTTONS 5 - struct soc_button_info { const char *name; int acpi_index; @@ -79,14 +72,19 @@ soc_button_device_create(struct platform_device *pdev, int gpio; int error; + for (info = button_info; info->name; info++) + if (info->autorepeat == autorepeat) + n_buttons++; + gpio_keys_pdata = devm_kzalloc(&pdev->dev, sizeof(*gpio_keys_pdata) + - sizeof(*gpio_keys) * MAX_NBUTTONS, + sizeof(*gpio_keys) * n_buttons, GFP_KERNEL); if (!gpio_keys_pdata) return ERR_PTR(-ENOMEM); gpio_keys = (void *)(gpio_keys_pdata + 1); + n_buttons = 0; for (info = button_info; info->name; info++) { if (info->autorepeat != autorepeat) @@ -200,6 +198,11 @@ static int soc_button_probe(struct platform_device *pdev) return 0; } +/* + * Definition of buttons on the tablet. The ACPI index of each button + * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC + * Platforms" + */ static struct soc_button_info soc_button_PNP0C40[] = { { "power", 0, EV_KEY, KEY_POWER, false, true }, { "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, -- cgit From 4c3362f44980aba8e1e69cd6970effbd9f17dc69 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Mar 2017 14:03:54 -0700 Subject: Input: soc_button_array - add support for ACPI 6.0 Generic Button Device Windows 10 tablets with gpio buttons will typically use the ACPI 6.0 Generic Button Device with a HID of ACPI0011 for these buttons. The ACPI description for these in the ACPI0011 devices _DSD object uses something resembling HID descriptors, except that instead of indicating a bit index into a HID input report, the index indicates the _CRS index for the GPIO. The use of 1 interrupt per button, some of which need to be wakeup sources, instead of using input reports makes it impossible to use the HID subsystem for this. This really is just another gpio-keys input device with the platform data described in ACPI, so this commit adds parsing for this new way to describe gpio-keys to the soc_button_array driver. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 159 +++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index b8769f6e3601..95b787a63560 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -138,6 +138,153 @@ err_free_mem: return ERR_PTR(error); } +static int soc_button_get_acpi_object_int(const union acpi_object *obj) +{ + if (obj->type != ACPI_TYPE_INTEGER) + return -1; + + return obj->integer.value; +} + +/* Parse a single ACPI0011 _DSD button descriptor */ +static int soc_button_parse_btn_desc(struct device *dev, + const union acpi_object *desc, + int collection_uid, + struct soc_button_info *info) +{ + int upage, usage; + + if (desc->type != ACPI_TYPE_PACKAGE || + desc->package.count != 5 || + /* First byte should be 1 (control) */ + soc_button_get_acpi_object_int(&desc->package.elements[0]) != 1 || + /* Third byte should be collection uid */ + soc_button_get_acpi_object_int(&desc->package.elements[2]) != + collection_uid) { + dev_err(dev, "Invalid ACPI Button Descriptor\n"); + return -ENODEV; + } + + info->event_type = EV_KEY; + info->acpi_index = + soc_button_get_acpi_object_int(&desc->package.elements[1]); + upage = soc_button_get_acpi_object_int(&desc->package.elements[3]); + usage = soc_button_get_acpi_object_int(&desc->package.elements[4]); + + /* + * The UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e descriptors use HID + * usage page and usage codes, but otherwise the device is not HID + * compliant: it uses one irq per button instead of generating HID + * input reports and some buttons should generate wakeups where as + * others should not, so we cannot use the HID subsystem. + * + * Luckily all devices only use a few usage page + usage combinations, + * so we can simply check for the known combinations here. + */ + if (upage == 0x01 && usage == 0x81) { + info->name = "power"; + info->event_code = KEY_POWER; + info->wakeup = true; + } else if (upage == 0x07 && usage == 0xe3) { + info->name = "home"; + info->event_code = KEY_HOMEPAGE; + info->wakeup = true; + } else if (upage == 0x0c && usage == 0xe9) { + info->name = "volume_up"; + info->event_code = KEY_VOLUMEUP; + info->autorepeat = true; + } else if (upage == 0x0c && usage == 0xea) { + info->name = "volume_down"; + info->event_code = KEY_VOLUMEDOWN; + info->autorepeat = true; + } else { + dev_warn(dev, "Unknown button index %d upage %02x usage %02x, ignoring\n", + info->acpi_index, upage, usage); + info->name = "unknown"; + info->event_code = KEY_RESERVED; + } + + return 0; +} + +/* ACPI0011 _DSD btns descriptors UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e */ +static const u8 btns_desc_uuid[16] = { + 0x25, 0xd6, 0x6b, 0xfa, 0xe8, 0x9c, 0x0d, 0x47, + 0xa2, 0xc7, 0xb3, 0xca, 0x36, 0xc4, 0x28, 0x2e +}; + +/* Parse ACPI0011 _DSD button descriptors */ +static struct soc_button_info *soc_button_get_button_info(struct device *dev) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + const union acpi_object *desc, *el0, *uuid, *btns_desc = NULL; + struct soc_button_info *button_info; + acpi_status status; + int i, btn, collection_uid = -1; + + status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL, + &buf, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(dev, "ACPI _DSD object not found\n"); + return ERR_PTR(-ENODEV); + } + + /* Look for the Button Descriptors UUID */ + desc = buf.pointer; + for (i = 0; (i + 1) < desc->package.count; i += 2) { + uuid = &desc->package.elements[i]; + + if (uuid->type != ACPI_TYPE_BUFFER || + uuid->buffer.length != 16 || + desc->package.elements[i + 1].type != ACPI_TYPE_PACKAGE) { + break; + } + + if (memcmp(uuid->buffer.pointer, btns_desc_uuid, 16) == 0) { + btns_desc = &desc->package.elements[i + 1]; + break; + } + } + + if (!btns_desc) { + dev_err(dev, "ACPI Button Descriptors not found\n"); + return ERR_PTR(-ENODEV); + } + + /* The first package describes the collection */ + el0 = &btns_desc->package.elements[0]; + if (el0->type == ACPI_TYPE_PACKAGE && + el0->package.count == 5 && + /* First byte should be 0 (collection) */ + soc_button_get_acpi_object_int(&el0->package.elements[0]) == 0 && + /* Third byte should be 0 (top level collection) */ + soc_button_get_acpi_object_int(&el0->package.elements[2]) == 0) { + collection_uid = soc_button_get_acpi_object_int( + &el0->package.elements[1]); + } + if (collection_uid == -1) { + dev_err(dev, "Invalid Button Collection Descriptor\n"); + return ERR_PTR(-ENODEV); + } + + /* There are package.count - 1 buttons + 1 terminating empty entry */ + button_info = devm_kcalloc(dev, btns_desc->package.count, + sizeof(*button_info), GFP_KERNEL); + if (!button_info) + return ERR_PTR(-ENOMEM); + + /* Parse the button descriptors */ + for (i = 1, btn = 0; i < btns_desc->package.count; i++, btn++) { + if (soc_button_parse_btn_desc(dev, + &btns_desc->package.elements[i], + collection_uid, + &button_info[btn])) + return ERR_PTR(-ENODEV); + } + + return button_info; +} + static int soc_button_remove(struct platform_device *pdev) { struct soc_button_data *priv = platform_get_drvdata(pdev); @@ -165,7 +312,13 @@ static int soc_button_probe(struct platform_device *pdev) if (!id) return -ENODEV; - button_info = (struct soc_button_info *)id->driver_data; + if (!id->driver_data) { + button_info = soc_button_get_button_info(dev); + if (IS_ERR(button_info)) + return PTR_ERR(button_info); + } else { + button_info = (struct soc_button_info *)id->driver_data; + } if (gpiod_count(dev, NULL) <= 0) { dev_dbg(dev, "no GPIO attached, ignoring...\n"); @@ -195,6 +348,9 @@ static int soc_button_probe(struct platform_device *pdev) if (!priv->children[0] && !priv->children[1]) return -ENODEV; + if (!id->driver_data) + devm_kfree(dev, button_info); + return 0; } @@ -214,6 +370,7 @@ static struct soc_button_info soc_button_PNP0C40[] = { static const struct acpi_device_id soc_button_acpi_match[] = { { "PNP0C40", (unsigned long)soc_button_PNP0C40 }, + { "ACPI0011", 0 }, { } }; -- cgit From fef5f569db06ea80ae3a864b1ba4bda6e359311d Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 17 Mar 2017 17:15:38 -0700 Subject: Input: convert remaining uses of pr_warning to pr_warn To enable eventual removal of pr_warning This makes pr_warn use consistent for drivers/input Prior to this patch, there were 8 uses of pr_warning and 17 uses of pr_warn in drivers/input Signed-off-by: Joe Perches Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 4 ++-- drivers/input/joystick/gamecon.c | 3 ++- drivers/input/misc/apanel.c | 3 ++- drivers/input/misc/xen-kbdfront.c | 8 ++++---- drivers/input/serio/serio.c | 8 ++++---- 5 files changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 4a2a9e370be7..092cc4188b57 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -385,8 +385,8 @@ static int gameport_queue_event(void *object, struct module *owner, } if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); + pr_warn("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index eae14d512353..c43f087a496d 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -870,7 +870,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) err = gc_n64_init_ff(input_dev, idx); if (err) { - pr_warning("Failed to initiate rumble for N64 device %d\n", idx); + pr_warn("Failed to initiate rumble for N64 device %d\n", + idx); goto err_free_dev; } diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index 53630afab606..aad1df04c854 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -314,7 +314,8 @@ static int __init apanel_init(void) if (devno >= APANEL_DEV_MAX) pr_notice(APANEL ": unknown device %u found\n", devno); else if (device_chip[devno] != CHIP_NONE) - pr_warning(APANEL ": duplicate entry for devno %u\n", devno); + pr_warn(APANEL ": duplicate entry for devno %u\n", + devno); else if (method != 1 && method != 2 && method != 4) { pr_notice(APANEL ": unknown method %u for devno %u\n", diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 3900875dec10..1fd911d4fadf 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -84,8 +84,8 @@ static irqreturn_t input_handler(int rq, void *dev_id) input_report_key(dev, event->key.keycode, event->key.pressed); else - pr_warning("unhandled keycode 0x%x\n", - event->key.keycode); + pr_warn("unhandled keycode 0x%x\n", + event->key.keycode); break; case XENKBD_TYPE_POS: input_report_abs(dev, ABS_X, event->pos.abs_x); @@ -133,7 +133,7 @@ static int xenkbd_probe(struct xenbus_device *dev, ret = xenbus_write(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); if (ret) { - pr_warning("xenkbd: can't request abs-pointer"); + pr_warn("xenkbd: can't request abs-pointer\n"); abs = 0; } } @@ -327,7 +327,7 @@ InitWait: ret = xenbus_write(XBT_NIL, info->xbdev->nodename, "request-abs-pointer", "1"); if (ret) - pr_warning("xenkbd: can't request abs-pointer"); + pr_warn("xenkbd: can't request abs-pointer\n"); } xenbus_switch_state(dev, XenbusStateConnected); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 1ca7f551e2da..048ae748c4d1 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -285,8 +285,8 @@ static int serio_queue_event(void *object, struct module *owner, } if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); + pr_warn("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; @@ -823,8 +823,8 @@ static void serio_attach_driver(struct serio_driver *drv) error = driver_attach(&drv->driver); if (error) - pr_warning("driver_attach() failed for %s with error %d\n", - drv->driver.name, error); + pr_warn("driver_attach() failed for %s with error %d\n", + drv->driver.name, error); } int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) -- cgit From 483e55d973473886d1c2c2785ee51b209c434950 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Feb 2017 00:44:28 -0800 Subject: Input: silead - add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. As pointed by Hans de Goede, there's no mssl1680 and this is just used in some ACPI systems to identify the gsl1680 chip. So isn't included in the OF device ID table since a DT should use the proper device name instead. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/silead.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 404830a4a366..813dd68a5c82 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -580,12 +580,25 @@ static const struct acpi_device_id silead_ts_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match); #endif +#ifdef CONFIG_OF +static const struct of_device_id silead_ts_of_match[] = { + { .compatible = "silead,gsl1680" }, + { .compatible = "silead,gsl1688" }, + { .compatible = "silead,gsl3670" }, + { .compatible = "silead,gsl3675" }, + { .compatible = "silead,gsl3692" }, + { }, +}; +MODULE_DEVICE_TABLE(of, silead_ts_of_match); +#endif + static struct i2c_driver silead_ts_driver = { .probe = silead_ts_probe, .id_table = silead_ts_id, .driver = { .name = SILEAD_TS_NAME, .acpi_match_table = ACPI_PTR(silead_ts_acpi_match), + .of_match_table = of_match_ptr(silead_ts_of_match), .pm = &silead_ts_pm, }, }; -- cgit From 72bf60f19661e0451071f6a2f1940f9af1a3e33b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Mar 2017 13:31:50 -0700 Subject: Input: synaptics_i2c - add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index cb2bf203f4ca..8538318d332c 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -652,9 +652,18 @@ static const struct i2c_device_id synaptics_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); +#ifdef CONFIG_OF +static const struct of_device_id synaptics_i2c_of_match[] = { + { .compatible = "synaptics,synaptics_i2c", }, + { }, +}; +MODULE_DEVICE_TABLE(of, synaptics_i2c_of_match); +#endif + static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, + .of_match_table = of_match_ptr(synaptics_i2c_of_match), .pm = &synaptics_i2c_pm, }, -- cgit From cf5cd9d4480a87da78768718cac194a71079b5cb Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Mar 2017 13:33:12 -0700 Subject: Input: qt1070 - add OF device ID table The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. The compatible strings don't have a vendor prefix because that's how it's used currently, and changing this will be a Device Tree ABI break. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/qt1070.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 5a5778729e37..76bb51309a78 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -274,9 +274,18 @@ static const struct i2c_device_id qt1070_id[] = { }; MODULE_DEVICE_TABLE(i2c, qt1070_id); +#ifdef CONFIG_OF +static const struct of_device_id qt1070_of_match[] = { + { .compatible = "qt1070", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qt1070_of_match); +#endif + static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", + .of_match_table = of_match_ptr(qt1070_of_match), .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, -- cgit From 996b9eedd061752bfa0f3a10381515d67db26b3e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 10:02:50 -0700 Subject: Input: synaptics - do not mix logical and bitwise operations Let's stop using !!x to reduce value of trackstick button expression to 0/1 and use shift instead. This removes the following sparse warning: CHECK drivers/input/mouse/synaptics.c drivers/input/mouse/synaptics.c:943:79: warning: dubious: !x | y Also, the bits we are testing are not capabilities, so lets drop "_CAP" suffix from macro names. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 6 +++--- drivers/input/mouse/synaptics.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 597ee4b01d9f..6a23c21968c1 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -884,9 +884,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, u8 pt_buttons; /* The trackstick expects at most 3 buttons */ - pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) | - SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | - SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; + pt_buttons = SYN_EXT_BUTTON_STICK_L(hw->ext_buttons) | + SYN_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | + SYN_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; serio_interrupt(priv->pt_port, PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 116ae2546ace..b76bb7a38472 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -111,9 +111,9 @@ #define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) #define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) -#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01)) -#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02)) -#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04)) +#define SYN_EXT_BUTTON_STICK_L(eb) (((eb) & BIT(0)) >> 0) +#define SYN_EXT_BUTTON_STICK_M(eb) (((eb) & BIT(1)) >> 1) +#define SYN_EXT_BUTTON_STICK_R(eb) (((eb) & BIT(2)) >> 2) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -- cgit From 5ea1320653359dd2ade7ff2ad81e37b790eb1f1f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Mar 2017 11:47:40 -0800 Subject: Input: serio - add fast reconnect option Devices connected to serio bus are quite slow, and to improve apparent speed of resume process, serio core resumes (reconnects) its devices asynchronously, by posting port reconnect requests to a workqueue. Unfortunately this means that if there is a dependent device of a given serio port (for example SMBus part of touchpad connected via both PS/2 and SMBus), we do not have a good way of ensuring resume order. This change allows drivers to define "fast reconnect" handlers that would be called in-line during system resume. Drivers need to ensure that these handlers are truly "fast". Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 048ae748c4d1..30d6230d48f7 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -953,12 +953,24 @@ static int serio_suspend(struct device *dev) static int serio_resume(struct device *dev) { struct serio *serio = to_serio_port(dev); + int error = -ENOENT; - /* - * Driver reconnect can take a while, so better let kseriod - * deal with it. - */ - serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); + mutex_lock(&serio->drv_mutex); + if (serio->drv && serio->drv->fast_reconnect) { + error = serio->drv->fast_reconnect(serio); + if (error && error != -ENOENT) + dev_warn(dev, "fast reconnect failed with error %d\n", + error); + } + mutex_unlock(&serio->drv_mutex); + + if (error) { + /* + * Driver reconnect can take a while, so better let + * kseriod deal with it. + */ + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); + } return 0; } -- cgit From 0ab3fa57425023f42e8822a293d9b87a3ad4e2b3 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Mar 2017 23:19:22 -0800 Subject: Input: psmouse - implement fast reconnect option Make use of serio's fast reconnect option and allow psmouse protocol handler's to implement fast reconnect handlers that will be called during system resume. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 30 +++++++++++++++++++++++++++--- drivers/input/mouse/psmouse.h | 1 + 2 files changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a598b7223cef..47fd2976da7f 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -966,6 +966,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) psmouse->protocol_handler = psmouse_process_byte; psmouse->pktsize = 3; psmouse->reconnect = NULL; + psmouse->fast_reconnect = NULL; psmouse->disconnect = NULL; psmouse->cleanup = NULL; psmouse->pt_activate = NULL; @@ -1628,15 +1629,26 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; } -static int psmouse_reconnect(struct serio *serio) +static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) { struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; + int (*reconnect_handler)(struct psmouse *); unsigned char type; int rc = -1; mutex_lock(&psmouse_mutex); + if (fast_reconnect) { + reconnect_handler = psmouse->fast_reconnect; + if (!reconnect_handler) { + rc = -ENOENT; + goto out_unlock; + } + } else { + reconnect_handler = psmouse->reconnect; + } + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); @@ -1644,8 +1656,8 @@ static int psmouse_reconnect(struct serio *serio) psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - if (psmouse->reconnect) { - if (psmouse->reconnect(psmouse)) + if (reconnect_handler) { + if (reconnect_handler(psmouse)) goto out; } else { psmouse_reset(psmouse); @@ -1677,10 +1689,21 @@ out: if (parent) psmouse_activate(parent); +out_unlock: mutex_unlock(&psmouse_mutex); return rc; } +static int psmouse_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, false); +} + +static int psmouse_fast_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, true); +} + static struct serio_device_id psmouse_serio_ids[] = { { .type = SERIO_8042, @@ -1708,6 +1731,7 @@ static struct serio_driver psmouse_drv = { .interrupt = psmouse_interrupt, .connect = psmouse_connect, .reconnect = psmouse_reconnect, + .fast_reconnect = psmouse_fast_reconnect, .disconnect = psmouse_disconnect, .cleanup = psmouse_cleanup, }; diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 8c83b8e2505c..bc76e771812b 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -80,6 +80,7 @@ struct psmouse { void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale); int (*reconnect)(struct psmouse *psmouse); + int (*fast_reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); void (*cleanup)(struct psmouse *psmouse); int (*poll)(struct psmouse *psmouse); -- cgit From 085fa80dfdd60ac58137a5b5d231e70456126fda Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 3 Mar 2017 15:29:00 -0800 Subject: Input: psmouse - store pointer to current protocol Instead of storing only protocol "type" in pmsouse structure, store pointer to the protocol structure, so that we have access to more data without having to copy it over to psmouse structure. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 43 +++++++++-------------- drivers/input/mouse/psmouse.h | 70 ++++++++++++++++++++++---------------- 2 files changed, 58 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 47fd2976da7f..bb5d164849ea 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -116,17 +116,6 @@ static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; -struct psmouse_protocol { - enum psmouse_type type; - bool maxproto; - bool ignore_parity; /* Protocol should ignore parity errors from KBC */ - bool try_passthru; /* Try protocol also on passthrough ports */ - const char *name; - const char *alias; - int (*detect)(struct psmouse *, bool); - int (*init)(struct psmouse *); -}; - static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) { input_report_key(dev, BTN_LEFT, buttons & BIT(0)); @@ -148,7 +137,7 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) /* Full packet accumulated, process it */ - switch (psmouse->type) { + switch (psmouse->protocol->type) { case PSMOUSE_IMPS: /* IntelliMouse has scroll wheel */ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); @@ -325,7 +314,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; if (unlikely((flags & SERIO_TIMEOUT) || - ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { + ((flags & SERIO_PARITY) && + !psmouse->protocol->ignore_parity))) { if (psmouse->state == PSMOUSE_ACTIVATED) psmouse_warn(psmouse, @@ -372,7 +362,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } if (psmouse->packet[1] == PSMOUSE_RET_ID || - (psmouse->type == PSMOUSE_HGPK && + (psmouse->protocol->type == PSMOUSE_HGPK && psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); @@ -959,6 +949,8 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + psmouse->protocol = &psmouse_protocols[0]; + psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; psmouse->set_scale = psmouse_set_scale; @@ -1476,6 +1468,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, { const struct psmouse_protocol *selected_proto; struct input_dev *input_dev = psmouse->dev; + enum psmouse_type type; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; @@ -1488,15 +1481,13 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, if (proto->init && proto->init(psmouse) < 0) return -1; - psmouse->type = proto->type; selected_proto = proto; } else { - psmouse->type = psmouse_extensions(psmouse, - psmouse_max_proto, true); - selected_proto = psmouse_protocol_by_type(psmouse->type); + type = psmouse_extensions(psmouse, psmouse_max_proto, true); + selected_proto = psmouse_protocol_by_type(type); } - psmouse->ignore_parity = selected_proto->ignore_parity; + psmouse->protocol = selected_proto; /* * If mouse's packet size is 3 there is no point in polling the @@ -1522,7 +1513,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, input_dev->phys = psmouse->phys; input_dev->id.bustype = BUS_I8042; input_dev->id.vendor = 0x0002; - input_dev->id.product = psmouse->type; + input_dev->id.product = psmouse->protocol->type; input_dev->id.version = psmouse->model; return 0; @@ -1634,7 +1625,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; int (*reconnect_handler)(struct psmouse *); - unsigned char type; + enum psmouse_type type; int rc = -1; mutex_lock(&psmouse_mutex); @@ -1666,7 +1657,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) goto out; type = psmouse_extensions(psmouse, psmouse_max_proto, false); - if (psmouse->type != type) + if (psmouse->protocol->type != type) goto out; } @@ -1816,7 +1807,7 @@ static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) { - return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); + return sprintf(buf, "%s\n", psmouse->protocol->name); } static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) @@ -1832,7 +1823,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!proto) return -EINVAL; - if (psmouse->type == proto->type) + if (psmouse->protocol == proto) return count; new_dev = input_allocate_device(); @@ -1856,7 +1847,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co return -ENODEV; } - if (psmouse->type == proto->type) { + if (psmouse->protocol == proto) { input_free_device(new_dev); return count; /* switched by other thread */ } @@ -1869,7 +1860,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co } old_dev = psmouse->dev; - old_proto = psmouse_protocol_by_type(psmouse->type); + old_proto = psmouse->protocol; if (psmouse->disconnect) psmouse->disconnect(psmouse); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index bc76e771812b..36bd42179456 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -44,21 +44,58 @@ enum psmouse_scale { PSMOUSE_SCALE21 }; +enum psmouse_type { + PSMOUSE_NONE, + PSMOUSE_PS2, + PSMOUSE_PS2PP, + PSMOUSE_THINKPS, + PSMOUSE_GENPS, + PSMOUSE_IMPS, + PSMOUSE_IMEX, + PSMOUSE_SYNAPTICS, + PSMOUSE_ALPS, + PSMOUSE_LIFEBOOK, + PSMOUSE_TRACKPOINT, + PSMOUSE_TOUCHKIT_PS2, + PSMOUSE_CORTRON, + PSMOUSE_HGPK, + PSMOUSE_ELANTECH, + PSMOUSE_FSP, + PSMOUSE_SYNAPTICS_RELATIVE, + PSMOUSE_CYPRESS, + PSMOUSE_FOCALTECH, + PSMOUSE_VMMOUSE, + PSMOUSE_BYD, + PSMOUSE_AUTO /* This one should always be last */ +}; + +struct psmouse; + +struct psmouse_protocol { + enum psmouse_type type; + bool maxproto; + bool ignore_parity; /* Protocol should ignore parity errors from KBC */ + bool try_passthru; /* Try protocol also on passthrough ports */ + const char *name; + const char *alias; + int (*detect)(struct psmouse *, bool); + int (*init)(struct psmouse *); +}; + struct psmouse { void *private; struct input_dev *dev; struct ps2dev ps2dev; struct delayed_work resync_work; - char *vendor; - char *name; + const char *vendor; + const char *name; + const struct psmouse_protocol *protocol; unsigned char packet[8]; unsigned char badbyte; unsigned char pktcnt; unsigned char pktsize; - unsigned char type; unsigned char oob_data_type; unsigned char extra_buttons; - bool ignore_parity; bool acks_disable_command; unsigned int model; unsigned long last; @@ -89,31 +126,6 @@ struct psmouse { void (*pt_deactivate)(struct psmouse *psmouse); }; -enum psmouse_type { - PSMOUSE_NONE, - PSMOUSE_PS2, - PSMOUSE_PS2PP, - PSMOUSE_THINKPS, - PSMOUSE_GENPS, - PSMOUSE_IMPS, - PSMOUSE_IMEX, - PSMOUSE_SYNAPTICS, - PSMOUSE_ALPS, - PSMOUSE_LIFEBOOK, - PSMOUSE_TRACKPOINT, - PSMOUSE_TOUCHKIT_PS2, - PSMOUSE_CORTRON, - PSMOUSE_HGPK, - PSMOUSE_ELANTECH, - PSMOUSE_FSP, - PSMOUSE_SYNAPTICS_RELATIVE, - PSMOUSE_CYPRESS, - PSMOUSE_FOCALTECH, - PSMOUSE_VMMOUSE, - PSMOUSE_BYD, - PSMOUSE_AUTO /* This one should always be last */ -}; - void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, unsigned long delay); int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); -- cgit From c774326a219536ab615d68a22875673f6f608b62 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 2 Mar 2017 15:50:56 -0800 Subject: Input: psmouse - introduce notion of SMBus companions Prepare PS/2 mouse drivers to work with devices that are accessible both via PS/2 and SMBus, which provides higher bandwidth, and thus suits better for modern multi-touch devices. We expect that SMBus drivers will take control over the device, so when we detect SMBus "protocol" we forego registering input device, or enabling PS/2 device reports (as it usually makes device unresponsive to access over SMBus). Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 103 +++++++++++++++++++++++++------------ drivers/input/mouse/psmouse.h | 1 + 2 files changed, 71 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index bb5d164849ea..a84f8ed2ba5d 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1424,9 +1424,8 @@ static void psmouse_cleanup(struct serio *serio) */ static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse, *parent = NULL; - - psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *parent = NULL; sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); @@ -1454,7 +1453,10 @@ static void psmouse_disconnect(struct serio *serio) serio_close(serio); serio_set_drvdata(serio, NULL); - input_unregister_device(psmouse->dev); + + if (psmouse->dev) + input_unregister_device(psmouse->dev); + kfree(psmouse); if (parent) @@ -1575,12 +1577,18 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_switch_protocol(psmouse, NULL); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - error = input_register_device(psmouse->dev); - if (error) - goto err_protocol_disconnect; + error = input_register_device(input_dev); + if (error) + goto err_protocol_disconnect; + } else { + /* Smbus companion will be reporting events, not us. */ + input_free_device(input_dev); + psmouse->dev = input_dev = NULL; + } if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -1589,7 +1597,12 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (error) goto err_pt_deactivate; - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); out: /* If this is a pass-through port the parent needs to be re-activated */ @@ -1602,8 +1615,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) err_pt_deactivate: if (parent && parent->pt_deactivate) parent->pt_deactivate(parent); - input_unregister_device(psmouse->dev); - input_dev = NULL; /* so we don't try to free it below */ + if (input_dev) { + input_unregister_device(input_dev); + input_dev = NULL; /* so we don't try to free it below */ + } err_protocol_disconnect: if (psmouse->disconnect) psmouse->disconnect(psmouse); @@ -1665,14 +1680,21 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) * OK, the device type (and capabilities) match the old one, * we can continue using it, complete initialization */ - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); + } if (parent && parent->pt_activate) parent->pt_activate(parent); - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); + rc = 0; out: @@ -1732,9 +1754,11 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de { struct serio *serio = to_serio_port(dev); struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse; + struct psmouse *psmouse = serio_get_drvdata(serio); - psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) + return -ENOENT; return attr->show(psmouse, attr->data, buf); } @@ -1753,6 +1777,12 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) { + retval = -ENOENT; + goto out_unlock; + } + if (attr->protect) { if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; @@ -1764,13 +1794,14 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse_deactivate(parent); } - psmouse_deactivate(psmouse); + if (!psmouse->protocol->smbus_companion) + psmouse_deactivate(psmouse); } retval = attr->set(psmouse, attr->data, buf, count); if (attr->protect) { - if (retval != -ENODEV) + if (retval != -ENODEV && !psmouse->protocol->smbus_companion) psmouse_activate(psmouse); if (parent) @@ -1879,23 +1910,29 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse_initialize(psmouse); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - error = input_register_device(psmouse->dev); - if (error) { - if (psmouse->disconnect) - psmouse->disconnect(psmouse); + if (psmouse->protocol->smbus_companion) { + input_free_device(psmouse->dev); + psmouse->dev = NULL; + } else { + error = input_register_device(psmouse->dev); + if (error) { + if (psmouse->disconnect) + psmouse->disconnect(psmouse); - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_free_device(new_dev); - psmouse->dev = old_dev; - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - psmouse_switch_protocol(psmouse, old_proto); - psmouse_initialize(psmouse); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_set_state(psmouse, PSMOUSE_IGNORE); + input_free_device(new_dev); + psmouse->dev = old_dev; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + psmouse_switch_protocol(psmouse, old_proto); + psmouse_initialize(psmouse); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - return error; + return error; + } } - input_unregister_device(old_dev); + if (old_dev) + input_unregister_device(old_dev); if (parent && parent->pt_activate) parent->pt_activate(parent); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 36bd42179456..e853dee05e79 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -76,6 +76,7 @@ struct psmouse_protocol { bool maxproto; bool ignore_parity; /* Protocol should ignore parity errors from KBC */ bool try_passthru; /* Try protocol also on passthrough ports */ + bool smbus_companion; /* "Protocol" is a stub, device is on SMBus */ const char *name; const char *alias; int (*detect)(struct psmouse *, bool); -- cgit From 8eb92e5c91338eb19f86ffb2232258337ebf905b Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Mar 2017 10:48:23 -0800 Subject: Input: psmouse - add support for SMBus companions This provides glue between PS/2 devices that enumerate the RMI4 devices and Elan touchpads to the RMI4 (or Elan) SMBus driver. The SMBus devices keep their PS/2 connection alive. If the initialization process goes too far (psmouse_activate called), the device disconnects from the I2C bus and stays on the PS/2 bus, that is why we explicitly disable PS/2 device reporting (by calling psmouse_deactivate) before trying to register SMBus companion device. The HID over I2C devices are enumerated through the ACPI DSDT, and their PS/2 device also exports the InterTouch bit in the extended capability 0x0C. However, the firmware keeps its I2C connection open even after going further in the PS/2 initialization. We don't need to take extra precautions with those device, especially because they block their PS/2 communication when HID over I2C is used. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 4 + drivers/input/mouse/Makefile | 2 + drivers/input/mouse/psmouse-base.c | 16 +- drivers/input/mouse/psmouse-smbus.c | 294 ++++++++++++++++++++++++++++++++++++ drivers/input/mouse/psmouse.h | 29 ++++ 5 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 drivers/input/mouse/psmouse-smbus.c (limited to 'drivers') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 096abb4ad5cd..87bde8a210c7 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -171,6 +171,10 @@ config MOUSE_PS2_VMMOUSE If unsure, say N. +config MOUSE_PS2_SMBUS + bool + depends on MOUSE_PS2 + config MOUSE_SERIAL tristate "Serial mouse" select SERIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 6168b134937b..56bf0ad877c6 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -39,6 +39,8 @@ psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o psmouse-$(CONFIG_MOUSE_PS2_VMMOUSE) += vmmouse.o +psmouse-$(CONFIG_MOUSE_PS2_SMBUS) += psmouse-smbus.o + elan_i2c-objs := elan_i2c_core.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_SMBUS) += elan_i2c_smbus.o diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a84f8ed2ba5d..ab9bfe2af381 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1999,16 +1999,27 @@ static int __init psmouse_init(void) synaptics_module_init(); hgpk_module_init(); + err = psmouse_smbus_module_init(); + if (err) + return err; + kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); if (!kpsmoused_wq) { pr_err("failed to create kpsmoused workqueue\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_smbus_exit; } err = serio_register_driver(&psmouse_drv); if (err) - destroy_workqueue(kpsmoused_wq); + goto err_destroy_wq; + return 0; + +err_destroy_wq: + destroy_workqueue(kpsmoused_wq); +err_smbus_exit: + psmouse_smbus_module_exit(); return err; } @@ -2016,6 +2027,7 @@ static void __exit psmouse_exit(void) { serio_unregister_driver(&psmouse_drv); destroy_workqueue(kpsmoused_wq); + psmouse_smbus_module_exit(); } module_init(psmouse_init); diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c new file mode 100644 index 000000000000..061c1cc44aef --- /dev/null +++ b/drivers/input/mouse/psmouse-smbus.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2017 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include "psmouse.h" + +struct psmouse_smbus_dev { + struct i2c_board_info board; + struct psmouse *psmouse; + struct i2c_client *client; + struct list_head node; + bool dead; +}; + +static LIST_HEAD(psmouse_smbus_list); +static DEFINE_MUTEX(psmouse_smbus_mutex); + +static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) +{ + struct psmouse_smbus_dev *smbdev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry(smbdev, &psmouse_smbus_list, node) { + if (smbdev->dead) + continue; + + if (smbdev->client) + continue; + + /* + * Here would be a good place to check if device is actually + * present, but it seems that SMBus will not respond unless we + * fully reset PS/2 connection. So cross our fingers, and try + * to switch over, hopefully our system will not have too many + * "host notify" I2C adapters. + */ + psmouse_dbg(smbdev->psmouse, + "SMBus candidate adapter appeared, triggering rescan\n"); + serio_rescan(smbdev->psmouse->ps2dev.serio); + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) +{ + struct psmouse_smbus_dev *smbdev; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry(smbdev, &psmouse_smbus_list, node) { + if (smbdev->client == client) { + psmouse_dbg(smbdev->psmouse, + "Marking SMBus companion %s as gone\n", + dev_name(&smbdev->client->dev)); + smbdev->client = NULL; + smbdev->dead = true; + serio_rescan(smbdev->psmouse->ps2dev.serio); + } + } + + kfree(client->dev.platform_data); + client->dev.platform_data = NULL; + + mutex_unlock(&psmouse_smbus_mutex); +} + +static int psmouse_smbus_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->type == &i2c_adapter_type) + psmouse_smbus_check_adapter(to_i2c_adapter(dev)); + break; + + case BUS_NOTIFY_REMOVED_DEVICE: + if (dev->type != &i2c_adapter_type) + psmouse_smbus_detach_i2c_client(to_i2c_client(dev)); + break; + } + + return 0; +} + +static struct notifier_block psmouse_smbus_notifier = { + .notifier_call = psmouse_smbus_notifier_call, +}; + +static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse) +{ + return PSMOUSE_FULL_PACKET; +} + +static int psmouse_smbus_reconnect(struct psmouse *psmouse) +{ + psmouse_deactivate(psmouse); + + return 0; +} + +struct psmouse_smbus_removal_work { + struct work_struct work; + struct i2c_client *client; +}; + +static void psmouse_smbus_remove_i2c_device(struct work_struct *work) +{ + struct psmouse_smbus_removal_work *rwork = + container_of(work, struct psmouse_smbus_removal_work, work); + + dev_dbg(&rwork->client->dev, "destroying SMBus companion device\n"); + i2c_unregister_device(rwork->client); + + kfree(rwork); +} + +/* + * This schedules removal of SMBus companion device. We have to do + * it in a separate tread to avoid deadlocking on psmouse_mutex in + * case the device has a trackstick (which is also driven by psmouse). + * + * Note that this may be racing with i2c adapter removal, but we + * can't do anything about that: i2c automatically destroys clients + * attached to an adapter that is being removed. This has to be + * fixed in i2c core. + */ +static void psmouse_smbus_schedule_remove(struct i2c_client *client) +{ + struct psmouse_smbus_removal_work *rwork; + + rwork = kzalloc(sizeof(*rwork), GFP_KERNEL); + if (rwork) { + INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device); + rwork->client = client; + + schedule_work(&rwork->work); + } +} + +static void psmouse_smbus_disconnect(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev = psmouse->private; + + mutex_lock(&psmouse_smbus_mutex); + list_del(&smbdev->node); + mutex_unlock(&psmouse_smbus_mutex); + + if (smbdev->client) { + psmouse_dbg(smbdev->psmouse, + "posting removal request for SMBus companion %s\n", + dev_name(&smbdev->client->dev)); + psmouse_smbus_schedule_remove(smbdev->client); + } + + kfree(smbdev); + psmouse->private = NULL; +} + +static int psmouse_smbus_create_companion(struct device *dev, void *data) +{ + struct psmouse_smbus_dev *smbdev = data; + unsigned short addr_list[] = { smbdev->board.addr, I2C_CLIENT_END }; + struct i2c_adapter *adapter; + + adapter = i2c_verify_adapter(dev); + if (!adapter) + return 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return 0; + + smbdev->client = i2c_new_probed_device(adapter, &smbdev->board, + addr_list, NULL); + if (!smbdev->client) + return 0; + + /* We have our(?) device, stop iterating i2c bus. */ + return 1; +} + +void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev, *tmp; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (psmouse == smbdev->psmouse) { + list_del(&smbdev->node); + kfree(smbdev); + } + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs) +{ + struct psmouse_smbus_dev *smbdev; + int error; + + smbdev = kzalloc(sizeof(*smbdev), GFP_KERNEL); + if (!smbdev) + return -ENOMEM; + + smbdev->psmouse = psmouse; + smbdev->board = *board; + + smbdev->board.platform_data = kmemdup(pdata, pdata_size, GFP_KERNEL); + if (!smbdev->board.platform_data) { + kfree(smbdev); + return -ENOMEM; + } + + psmouse->private = smbdev; + psmouse->protocol_handler = psmouse_smbus_process_byte; + psmouse->reconnect = psmouse_smbus_reconnect; + psmouse->fast_reconnect = psmouse_smbus_reconnect; + psmouse->disconnect = psmouse_smbus_disconnect; + psmouse->resync_time = 0; + + psmouse_deactivate(psmouse); + + mutex_lock(&psmouse_smbus_mutex); + list_add_tail(&smbdev->node, &psmouse_smbus_list); + mutex_unlock(&psmouse_smbus_mutex); + + /* Bind to already existing adapters right away */ + error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion); + + if (smbdev->client) { + /* We have our companion device */ + return 0; + } + + /* + * If we did not create i2c device we will not need platform + * data even if we are leaving breadcrumbs. + */ + kfree(smbdev->board.platform_data); + smbdev->board.platform_data = NULL; + + if (error < 0 || !leave_breadcrumbs) { + mutex_lock(&psmouse_smbus_mutex); + list_del(&smbdev->node); + mutex_unlock(&psmouse_smbus_mutex); + + kfree(smbdev); + } + + return error < 0 ? error : -EAGAIN; +} + +int __init psmouse_smbus_module_init(void) +{ + int error; + + error = bus_register_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + if (error) { + pr_err("failed to register i2c bus notifier: %d\n", error); + return error; + } + + return 0; +} + +void psmouse_smbus_module_exit(void) +{ + bus_unregister_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + flush_scheduled_work(); +} diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e853dee05e79..05110832109c 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -209,5 +209,34 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ &(psmouse)->ps2dev.serio->dev, \ psmouse_fmt(format), ##__VA_ARGS__) +#ifdef CONFIG_MOUSE_PS2_SMBUS + +int psmouse_smbus_module_init(void); +void psmouse_smbus_module_exit(void); + +struct i2c_board_info; + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs); +void psmouse_smbus_cleanup(struct psmouse *psmouse); + +#else /* !CONFIG_MOUSE_PS2_SMBUS */ + +static inline int psmouse_smbus_module_init(void) +{ + return 0; +} + +static inline void psmouse_smbus_module_exit(void) +{ +} + +static inline void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ +} + +#endif /* CONFIG_MOUSE_PS2_SMBUS */ #endif /* _PSMOUSE_H */ -- cgit From 6c53694fb2223746738d1d0cea71456ca88c8fb2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 5 Mar 2017 15:51:33 -0800 Subject: Input: synaptics - split device info into a separate structure In preparation for SMBus/Intertouch device support, move static device information that we query form the touchpad upon initialization into separate structure. This will allow us to query the device without allocating memory first. Also stop using "unsigned long", everything fits into 32 bit chunks. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 392 ++++++++++++++++++++++------------------ drivers/input/mouse/synaptics.h | 28 +-- 2 files changed, 233 insertions(+), 187 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 6a23c21968c1..0e08e2d497e9 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -127,9 +127,9 @@ static bool cr48_profile_sensor; struct min_max_quirk { const char * const *pnp_ids; struct { - unsigned long int min, max; + u32 min, max; } board_id; - int x_min, x_max, y_min, y_max; + u32 x_min, x_max, y_min, y_max; }; static const struct min_max_quirk min_max_pnpid_table[] = { @@ -248,27 +248,31 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros */ -static int synaptics_model_id(struct psmouse *psmouse) +static int synaptics_model_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char mi[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) - return -1; - priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi); + if (error) + return error; + + info->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2]; return 0; } -static int synaptics_more_extended_queries(struct psmouse *psmouse) +static int synaptics_more_extended_queries(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char buf[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf)) - return -1; - - priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf); + if (error) + return error; + info->ext_cap_10 = (buf[0] << 16) | (buf[1] << 8) | buf[2]; return 0; } @@ -276,21 +280,24 @@ static int synaptics_more_extended_queries(struct psmouse *psmouse) * Read the board id and the "More Extended Queries" from the touchpad * The board id is encoded in the "QUERY MODES" response */ -static int synaptics_query_modes(struct psmouse *psmouse) +static int synaptics_query_modes(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char bid[3]; + int error; /* firmwares prior 7.5 have no board_id encoded */ - if (SYN_ID_FULL(priv->identity) < 0x705) + if (SYN_ID_FULL(info->identity) < 0x705) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid)) - return -1; - priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; + error = synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid); + if (error) + return error; + + info->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse); + return synaptics_more_extended_queries(psmouse, info); return 0; } @@ -298,14 +305,17 @@ static int synaptics_query_modes(struct psmouse *psmouse) /* * Read the firmware id from the touchpad */ -static int synaptics_firmware_id(struct psmouse *psmouse) +static int synaptics_firmware_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char fwid[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid)) - return -1; - priv->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; + error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); + if (error) + return error; + + info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; return 0; } @@ -313,53 +323,57 @@ static int synaptics_firmware_id(struct psmouse *psmouse) * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros */ -static int synaptics_capability(struct psmouse *psmouse) +static int synaptics_capability(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char cap[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) - return -1; - priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - priv->ext_cap = priv->ext_cap_0c = 0; + error = synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap); + if (error) + return error; + + info->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + info->ext_cap = info->ext_cap_0c = 0; /* * Older firmwares had submodel ID fixed to 0x47 */ - if (SYN_ID_FULL(priv->identity) < 0x705 && - SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) { - return -1; + if (SYN_ID_FULL(info->identity) < 0x705 && + SYN_CAP_SUBMODEL_ID(info->capabilities) != 0x47) { + return -ENXIO; } /* * Unless capExtended is set the rest of the flags should be ignored */ - if (!SYN_CAP_EXTENDED(priv->capabilities)) - priv->capabilities = 0; + if (!SYN_CAP_EXTENDED(info->capabilities)) + info->capabilities = 0; - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { psmouse_warn(psmouse, "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { - priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + info->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) - priv->ext_cap &= 0xff0fff; + if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8) + info->ext_cap &= 0xff0fff; } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) { + error = synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap); + if (error) psmouse_warn(psmouse, "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - } else { - priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - } + else + info->ext_cap_0c = + (cap[0] << 16) | (cap[1] << 8) | cap[2]; } return 0; @@ -369,17 +383,18 @@ static int synaptics_capability(struct psmouse *psmouse) * Identify Touchpad * See also the SYN_ID_* macros */ -static int synaptics_identify(struct psmouse *psmouse) +static int synaptics_identify(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char id[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) - return -1; - priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; - if (SYN_ID_IS_SYNAPTICS(priv->identity)) - return 0; - return -1; + error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + if (error) + return error; + + info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; + return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } /* @@ -387,52 +402,58 @@ static int synaptics_identify(struct psmouse *psmouse) * Resolution is left zero if touchpad does not support the query */ -static int synaptics_resolution(struct psmouse *psmouse) +static int synaptics_resolution(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; unsigned char resp[3]; + int error; - if (SYN_ID_MAJOR(priv->identity) < 4) + if (SYN_ID_MAJOR(info->identity) < 4) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) { + error = synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp); + if (!error) { if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) { - priv->x_res = resp[0]; /* x resolution in units/mm */ - priv->y_res = resp[2]; /* y resolution in units/mm */ + info->x_res = resp[0]; /* x resolution in units/mm */ + info->y_res = resp[2]; /* y resolution in units/mm */ } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && - SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 5 && + SYN_CAP_MAX_DIMENSIONS(info->ext_cap_0c)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MAX_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have max coordinates query, but I'm not able to read it.\n"); } else { - priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried max coordinates: x [..%d], y [..%d]\n", - priv->x_max, priv->y_max); + info->x_max, info->y_max); } } - if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) && - (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 || + if (SYN_CAP_MIN_DIMENSIONS(info->ext_cap_0c) && + (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 7 || /* * Firmware v8.1 does not report proper number of extended * capabilities, but has been proven to report correct min * coordinates. */ - SYN_ID_FULL(priv->identity) == 0x801)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { + SYN_ID_FULL(info->identity) == 0x801)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MIN_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have min coordinates query, but I'm not able to read it.\n"); } else { - priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried min coordinates: x [%d..], y [%d..]\n", - priv->x_min, priv->y_min); + info->x_min, info->y_min); } } @@ -443,9 +464,9 @@ static int synaptics_resolution(struct psmouse *psmouse) * Apply quirk(s) if the hardware matches */ -static void synaptics_apply_quirks(struct psmouse *psmouse) +static void synaptics_apply_quirks(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; int i; for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { @@ -454,41 +475,53 @@ static void synaptics_apply_quirks(struct psmouse *psmouse) continue; if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID && - priv->board_id < min_max_pnpid_table[i].board_id.min) + info->board_id < min_max_pnpid_table[i].board_id.min) continue; if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID && - priv->board_id > min_max_pnpid_table[i].board_id.max) + info->board_id > min_max_pnpid_table[i].board_id.max) continue; - priv->x_min = min_max_pnpid_table[i].x_min; - priv->x_max = min_max_pnpid_table[i].x_max; - priv->y_min = min_max_pnpid_table[i].y_min; - priv->y_max = min_max_pnpid_table[i].y_max; + info->x_min = min_max_pnpid_table[i].x_min; + info->x_max = min_max_pnpid_table[i].x_max; + info->y_min = min_max_pnpid_table[i].y_min; + info->y_max = min_max_pnpid_table[i].y_max; psmouse_info(psmouse, "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n", - priv->x_min, priv->x_max, - priv->y_min, priv->y_max); + info->x_min, info->x_max, + info->y_min, info->y_max); break; } } -static int synaptics_query_hardware(struct psmouse *psmouse) +static int synaptics_query_hardware(struct psmouse *psmouse, + struct synaptics_device_info *info) { - if (synaptics_identify(psmouse)) - return -1; - if (synaptics_model_id(psmouse)) - return -1; - if (synaptics_firmware_id(psmouse)) - return -1; - if (synaptics_query_modes(psmouse)) - return -1; - if (synaptics_capability(psmouse)) - return -1; - if (synaptics_resolution(psmouse)) - return -1; + int error; + + error = synaptics_identify(psmouse, info); + if (error) + return error; + + error = synaptics_model_id(psmouse, info); + if (error) + return error; + + error = synaptics_firmware_id(psmouse, info); + if (error) + return error; - synaptics_apply_quirks(psmouse); + error = synaptics_query_modes(psmouse, info); + if (error) + return error; + + error = synaptics_capability(psmouse, info); + if (error) + return error; + + error = synaptics_resolution(psmouse, info); + if (error) + return error; return 0; } @@ -498,8 +531,8 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; - if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) + if (!(SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c))) return 0; if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) @@ -509,7 +542,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) return -1; /* Advanced gesture mode also sends multi finger data */ - priv->capabilities |= BIT(1); + priv->info.capabilities |= BIT(1); return 0; } @@ -525,7 +558,7 @@ static int synaptics_set_mode(struct psmouse *psmouse) priv->mode |= SYN_BIT_DISABLE_GESTURE; if (psmouse->rate >= 80) priv->mode |= SYN_BIT_HIGH_RATE; - if (SYN_CAP_EXTENDED(priv->capabilities)) + if (SYN_CAP_EXTENDED(priv->info.capabilities)) priv->mode |= SYN_BIT_W_MODE; if (synaptics_mode_cmd(psmouse, priv->mode)) @@ -693,7 +726,7 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[], struct synaptics_hw_state *hw) { unsigned int ext_bits = - (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; unsigned int ext_mask = GENMASK(ext_bits - 1, 0); hw->ext_buttons = buf[4] & ext_mask; @@ -706,13 +739,13 @@ static int synaptics_parse_hw_state(const unsigned char buf[], { memset(hw, 0, sizeof(struct synaptics_hw_state)); - if (SYN_MODEL_NEWABS(priv->model_id)) { + if (SYN_MODEL_NEWABS(priv->info.model_id)) { hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); - if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + if ((SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c)) && hw->w == 2) { synaptics_parse_agm(buf, priv, hw); return 1; @@ -765,7 +798,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->left = priv->report_press; - } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + } else if (SYN_CAP_CLICKPAD(priv->info.ext_cap_0c)) { /* * Clickpad's button is transmitted as middle button, * however, since it is primary button, we will report @@ -773,18 +806,18 @@ static int synaptics_parse_hw_state(const unsigned char buf[], */ hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) hw->scroll = (signed char)(buf[1]); } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && + if (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) > 0 && ((buf[0] ^ buf[3]) & 0x02)) { synaptics_parse_ext_buttons(buf, priv, hw); } @@ -853,19 +886,19 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; int i; - if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) + if (!SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap)) return; /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */ - if ((SYN_ID_FULL(priv->identity) == 0x801 || - SYN_ID_FULL(priv->identity) == 0x802) && + if ((SYN_ID_FULL(priv->info.identity) == 0x801 || + SYN_ID_FULL(priv->info.identity) == 0x802) && !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02)) return; - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) { + if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) { for (i = 0; i < ext_bits; i++) { input_report_key(dev, BTN_0 + 2 * i, hw->ext_buttons & (1 << i)); @@ -903,10 +936,10 @@ static void synaptics_report_buttons(struct psmouse *psmouse, input_report_key(dev, BTN_LEFT, hw->left); input_report_key(dev, BTN_RIGHT, hw->right); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) input_report_key(dev, BTN_MIDDLE, hw->middle); - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { input_report_key(dev, BTN_FORWARD, hw->up); input_report_key(dev, BTN_BACK, hw->down); } @@ -931,7 +964,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, pos[i].y = synaptics_invert_y(hw[i]->y); } - input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); + input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->info.x_res); for (i = 0; i < nsemi; i++) { input_mt_slot(dev, slot[i]); @@ -985,6 +1018,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; + struct synaptics_device_info *info = &priv->info; struct synaptics_hw_state hw; int num_fingers; int finger_width; @@ -992,7 +1026,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) return; - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { synaptics_image_sensor_process(psmouse, &hw); return; } @@ -1020,18 +1054,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (hw.z > 0 && hw.x > 1) { num_fingers = 1; finger_width = 5; - if (SYN_CAP_EXTENDED(priv->capabilities)) { + if (SYN_CAP_EXTENDED(info->capabilities)) { switch (hw.w) { case 0 ... 1: - if (SYN_CAP_MULTIFINGER(priv->capabilities)) + if (SYN_CAP_MULTIFINGER(info->capabilities)) num_fingers = hw.w + 2; break; case 2: - if (SYN_MODEL_PEN(priv->model_id)) + if (SYN_MODEL_PEN(info->model_id)) ; /* Nothing, treat a pen as a single finger */ break; case 4 ... 15: - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) finger_width = hw.w; break; } @@ -1046,7 +1080,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) return; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) + if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) synaptics_report_semi_mt_data(dev, &hw, &priv->agm, num_fingers); @@ -1063,11 +1097,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) } input_report_abs(dev, ABS_PRESSURE, hw.z); - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } @@ -1129,7 +1163,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (SYN_CAP_PASS_THROUGH(priv->capabilities) && + if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) && synaptics_is_pt_packet(psmouse->packet)) { if (priv->pt_port) synaptics_pass_pt_packet(priv->pt_port, @@ -1148,26 +1182,27 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) * Driver initialization/cleanup functions ****************************************************************************/ static void set_abs_position_params(struct input_dev *dev, - struct synaptics_data *priv, int x_code, - int y_code) + struct synaptics_device_info *info, + int x_code, int y_code) { - int x_min = priv->x_min ?: XMIN_NOMINAL; - int x_max = priv->x_max ?: XMAX_NOMINAL; - int y_min = priv->y_min ?: YMIN_NOMINAL; - int y_max = priv->y_max ?: YMAX_NOMINAL; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? + int x_min = info->x_min ?: XMIN_NOMINAL; + int x_max = info->x_max ?: XMAX_NOMINAL; + int y_min = info->y_min ?: YMIN_NOMINAL; + int y_max = info->y_max ?: YMAX_NOMINAL; + int fuzz = SYN_CAP_REDUCED_FILTERING(info->ext_cap_0c) ? SYN_REDUCED_FILTER_FUZZ : 0; input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); - input_abs_set_res(dev, x_code, priv->x_res); - input_abs_set_res(dev, y_code, priv->y_res); + input_abs_set_res(dev, x_code, info->x_res); + input_abs_set_res(dev, y_code, info->y_res); } static void set_input_params(struct psmouse *psmouse, struct synaptics_data *priv) { struct input_dev *dev = psmouse->dev; + struct synaptics_device_info *info = &priv->info; int i; /* Things that apply to both modes */ @@ -1176,7 +1211,7 @@ static void set_input_params(struct psmouse *psmouse, __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(info->capabilities)) __set_bit(BTN_MIDDLE, dev->keybit); if (!priv->absolute_mode) { @@ -1189,15 +1224,15 @@ static void set_input_params(struct psmouse *psmouse, /* Absolute mode */ __set_bit(EV_ABS, dev->evbit); - set_abs_position_params(dev, priv, ABS_X, ABS_Y); + set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); if (cr48_profile_sensor) input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); @@ -1205,9 +1240,9 @@ static void set_input_params(struct psmouse *psmouse, /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); - } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + } else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* * Profile sensor in CR-48 tracks contacts reasonably well, * other non-image sensors with AGM use semi-mt. @@ -1218,35 +1253,35 @@ static void set_input_params(struct psmouse *psmouse, INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); } - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); __set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOOL_FINGER, dev->keybit); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || - SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(info->capabilities) || + SYN_CAP_MIDDLE_BUTTON(info->capabilities)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++) __set_bit(BTN_0 + i, dev->keybit); __clear_bit(EV_REL, dev->evbit); __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && - !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); /* Clickpads report only left button */ __clear_bit(BTN_RIGHT, dev->keybit); @@ -1300,7 +1335,8 @@ static void synaptics_disconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) + if (!priv->absolute_mode && + SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); @@ -1312,7 +1348,7 @@ static void synaptics_disconnect(struct psmouse *psmouse) static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - struct synaptics_data old_priv = *priv; + struct synaptics_device_info info; unsigned char param[2]; int retry = 0; int error; @@ -1339,7 +1375,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) if (retry > 1) psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - if (synaptics_query_hardware(psmouse)) { + if (synaptics_query_hardware(psmouse, &info)) { psmouse_err(psmouse, "Unable to query device.\n"); return -1; } @@ -1349,16 +1385,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) return -1; } - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) { + if (info.identity != priv->info.identity || + info.model_id != priv->info.model_id || + info.capabilities != priv->info.capabilities || + info.ext_cap != priv->info.ext_cap) { psmouse_err(psmouse, - "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); + "hardware appears to be different: id(%u-%u), model(%u-%u), caps(%x-%x), ext(%x-%x).\n", + priv->info.identity, info.identity, + priv->info.model_id, info.model_id, + priv->info.capabilities, info.capabilities, + priv->info.ext_cap, info.ext_cap); return -1; } @@ -1442,6 +1478,7 @@ void __init synaptics_module_init(void) static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) { struct synaptics_data *priv; + struct synaptics_device_info *info; int err = -1; /* @@ -1460,15 +1497,19 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) if (!priv) return -ENOMEM; + info = &priv->info; + psmouse_reset(psmouse); - if (synaptics_query_hardware(psmouse)) { + if (synaptics_query_hardware(psmouse, info)) { psmouse_err(psmouse, "Unable to query device.\n"); goto init_fail; } + synaptics_apply_quirks(psmouse, info); + priv->absolute_mode = absolute_mode; - if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) + if (SYN_ID_DISGEST_SUPPORTED(info->identity)) priv->disable_gesture = true; /* @@ -1482,15 +1523,16 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) goto init_fail; } - priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + priv->pkt_type = SYN_MODEL_NEWABS(info->model_id) ? + SYN_NEWABS : SYN_OLDABS; psmouse_info(psmouse, - "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->ext_cap_10, priv->board_id, priv->firmware_id); + "Touchpad model: %u, fw: %u.%u, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", + SYN_ID_MODEL(info->identity), + SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity), + info->model_id, + info->capabilities, info->ext_cap, info->ext_cap_0c, + info->ext_cap_10, info->board_id, info->firmware_id); set_input_params(psmouse, priv); @@ -1501,8 +1543,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) * Hardware info bits seem to be good candidates as they * are documented to be for Synaptics corp. internal use. */ - psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | - (priv->model_id & 0x000000ff); + psmouse->model = ((info->model_id & 0x00ff0000) >> 8) | + (info->model_id & 0x000000ff); if (absolute_mode) { psmouse->protocol_handler = synaptics_process_byte; @@ -1520,7 +1562,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) /* Synaptics can usually stay in sync without extra help */ psmouse->resync_time = 0; - if (SYN_CAP_PASS_THROUGH(priv->capabilities)) + if (SYN_CAP_PASS_THROUGH(info->capabilities)) synaptics_pt_create(psmouse); /* @@ -1535,7 +1577,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) psmouse->rate = 40; } - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) { + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(info->identity)) { err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); if (err) { diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index b76bb7a38472..d9b824fbddc2 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -161,19 +161,23 @@ struct synaptics_hw_state { signed char scroll; }; +/* Data read from the touchpad */ +struct synaptics_device_info { + u32 model_id; /* Model-ID */ + u32 firmware_id; /* Firmware-ID */ + u32 board_id; /* Board-ID */ + u32 capabilities; /* Capabilities */ + u32 ext_cap; /* Extended Capabilities */ + u32 ext_cap_0c; /* Ext Caps from 0x0c query */ + u32 ext_cap_10; /* Ext Caps from 0x10 query */ + u32 identity; /* Identification */ + u32 x_res, y_res; /* X/Y resolution in units/mm */ + u32 x_max, y_max; /* Max coordinates (from FW) */ + u32 x_min, y_min; /* Min coordinates (from FW) */ +}; + struct synaptics_data { - /* Data read from the touchpad */ - unsigned long int model_id; /* Model-ID */ - unsigned long int firmware_id; /* Firmware-ID */ - unsigned long int board_id; /* Board-ID */ - unsigned long int capabilities; /* Capabilities */ - unsigned long int ext_cap; /* Extended Capabilities */ - unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ - unsigned long int ext_cap_10; /* Ext Caps from 0x10 query */ - unsigned long int identity; /* Identification */ - unsigned int x_res, y_res; /* X/Y resolution in units/mm */ - unsigned int x_max, y_max; /* Max coordinates (from FW) */ - unsigned int x_min, y_min; /* Min coordinates (from FW) */ + struct synaptics_device_info info; unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ -- cgit From e839ffab028981ac77f650faf8c84f16e1719738 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 2 Mar 2017 14:13:53 -0800 Subject: Input: synaptics - add support for Intertouch devices Most of the Synaptics devices are connected through PS/2 and a different bus (SMBus or HID over I2C). The secondary bus capability is indicated by the InterTouch bit in extended capability 0x0C. We only enable the InterTouch device to be created for the laptops registered with the top software button property or those we know that are functional. In the future, we might change the default to always rely on the InterTouch bus. Currently, users can enable/disable the feature with the psmouse parameter synaptics_intertouch. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Kconfig | 12 + drivers/input/mouse/psmouse-base.c | 24 +- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/synaptics.c | 554 +++++++++++++++++++++++++------------ drivers/input/mouse/synaptics.h | 5 +- 5 files changed, 421 insertions(+), 175 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 87bde8a210c7..89ebb8f39fee 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -78,6 +78,18 @@ config MOUSE_PS2_SYNAPTICS If unsure, say Y. +config MOUSE_PS2_SYNAPTICS_SMBUS + bool "Synaptics PS/2 SMbus companion" if EXPERT + default y + depends on MOUSE_PS2 + depends on I2C=y || I2C=MOUSE_PS2 + select MOUSE_PS2_SMBUS + help + Say Y here if you have a Synaptics RMI4 touchpad connected to + to an SMBus, but enumerated through PS/2. + + If unsure, say Y. + config MOUSE_PS2_CYPRESS bool "Cypress PS/2 mouse protocol extension" if EXPERT default y diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index ab9bfe2af381..f73b47b8c578 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -773,7 +773,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "SynPS/2", .alias = "synaptics", .detect = synaptics_detect, - .init = synaptics_init, + .init = synaptics_init_absolute, }, { .type = PSMOUSE_SYNAPTICS_RELATIVE, @@ -783,6 +783,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .init = synaptics_init_relative, }, #endif +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + { + .type = PSMOUSE_SYNAPTICS_SMBUS, + .name = "SynSMBus", + .alias = "synaptics-smbus", + .detect = synaptics_detect, + .init = synaptics_init_smbus, + .smbus_companion = true, + }, +#endif #ifdef CONFIG_MOUSE_PS2_ALPS { .type = PSMOUSE_ALPS, @@ -1011,6 +1021,7 @@ static int psmouse_extensions(struct psmouse *psmouse, unsigned int max_proto, bool set_properties) { bool synaptics_hardware = false; + int ret; /* * Always check for focaltech, this is safe as it uses pnp-id @@ -1073,9 +1084,14 @@ static int psmouse_extensions(struct psmouse *psmouse, * enabled first, since we try detecting Synaptics * even when protocol is disabled. */ - if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && - (!set_properties || synaptics_init(psmouse) == 0)) { - return PSMOUSE_SYNAPTICS; + if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) || + IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) { + if (!set_properties) + return PSMOUSE_SYNAPTICS; + + ret = synaptics_init(psmouse); + if (ret >= 0) + return ret; } /* diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 05110832109c..38855e425f01 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -66,6 +66,7 @@ enum psmouse_type { PSMOUSE_FOCALTECH, PSMOUSE_VMMOUSE, PSMOUSE_BYD, + PSMOUSE_SYNAPTICS_SMBUS, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 0e08e2d497e9..d494c6c6aadc 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include "psmouse.h" #include "synaptics.h" @@ -119,59 +121,8 @@ void synaptics_reset(struct psmouse *psmouse) synaptics_mode_cmd(psmouse, 0); } -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - -static bool cr48_profile_sensor; - -#define ANY_BOARD_ID 0 -struct min_max_quirk { - const char * const *pnp_ids; - struct { - u32 min, max; - } board_id; - u32 x_min, x_max, y_min, y_max; -}; - -static const struct min_max_quirk min_max_pnpid_table[] = { - { - (const char * const []){"LEN0033", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5052, 2258, 4832 - }, - { - (const char * const []){"LEN0042", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1232, 5710, 1156, 4696 - }, - { - (const char * const []){"LEN0034", "LEN0036", "LEN0037", - "LEN0039", "LEN2002", "LEN2004", - NULL}, - {ANY_BOARD_ID, 2961}, - 1024, 5112, 2024, 4832 - }, - { - (const char * const []){"LEN2000", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5113, 2021, 4832 - }, - { - (const char * const []){"LEN2001", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5022, 2508, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {2691, 2691}, - 1024, 5045, 2457, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1264, 5675, 1171, 4688 - }, - { } -}; +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) /* This list has been kindly provided by Synaptics. */ static const char * const topbuttonpad_pnp_ids[] = { @@ -211,37 +162,50 @@ static const char * const topbuttonpad_pnp_ids[] = { NULL }; -/* This list has been kindly provided by Synaptics. */ -static const char * const forcepad_pnp_ids[] = { - "SYN300D", - "SYN3014", +static const char * const smbus_pnp_ids[] = { + /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ + "LEN0048", /* X1 Carbon 3 */ + "LEN0046", /* X250 */ + "LEN004a", /* W541 */ + "LEN200f", /* T450s */ NULL }; -/***************************************************************************** - * Synaptics communications functions - ****************************************************************************/ - /* - * Synaptics touchpads report the y coordinate from bottom to top, which is - * opposite from what userspace expects. - * This function is used to invert y before reporting. + * Send a command to the synpatics touchpad by special commands */ -static int synaptics_invert_y(int y) +static int synaptics_send_cmd(struct psmouse *psmouse, + unsigned char c, unsigned char *param) { - return YMAX_NOMINAL + YMIN_NOMINAL - y; + int error; + + error = psmouse_sliced_command(psmouse, c); + if (error) + return error; + + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO); + if (error) + return error; + + return 0; } /* - * Send a command to the synpatics touchpad by special commands + * Identify Touchpad + * See also the SYN_ID_* macros */ -static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) +static int synaptics_identify(struct psmouse *psmouse, + struct synaptics_device_info *info) { - if (psmouse_sliced_command(psmouse, c)) - return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - return 0; + unsigned char id[3]; + int error; + + error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + if (error) + return error; + + info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; + return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } /* @@ -262,6 +226,23 @@ static int synaptics_model_id(struct psmouse *psmouse, return 0; } +/* + * Read the firmware id from the touchpad + */ +static int synaptics_firmware_id(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + unsigned char fwid[3]; + int error; + + error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); + if (error) + return error; + + info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; + return 0; +} + static int synaptics_more_extended_queries(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -302,23 +283,6 @@ static int synaptics_query_modes(struct psmouse *psmouse, return 0; } -/* - * Read the firmware id from the touchpad - */ -static int synaptics_firmware_id(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char fwid[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); - if (error) - return error; - - info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; - return 0; -} - /* * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros @@ -379,29 +343,10 @@ static int synaptics_capability(struct psmouse *psmouse, return 0; } -/* - * Identify Touchpad - * See also the SYN_ID_* macros - */ -static int synaptics_identify(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char id[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); - if (error) - return error; - - info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; - return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; -} - /* * Read touchpad resolution and maximum reported coordinates * Resolution is left zero if touchpad does not support the query */ - static int synaptics_resolution(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -460,10 +405,118 @@ static int synaptics_resolution(struct psmouse *psmouse, return 0; } +static int synaptics_query_hardware(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + int error; + + error = synaptics_identify(psmouse, info); + if (error) + return error; + + error = synaptics_model_id(psmouse, info); + if (error) + return error; + + error = synaptics_firmware_id(psmouse, info); + if (error) + return error; + + error = synaptics_query_modes(psmouse, info); + if (error) + return error; + + error = synaptics_capability(psmouse, info); + if (error) + return error; + + error = synaptics_resolution(psmouse, info); + if (error) + return error; + + return 0; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS + +static bool cr48_profile_sensor; + +#define ANY_BOARD_ID 0 +struct min_max_quirk { + const char * const *pnp_ids; + struct { + u32 min, max; + } board_id; + u32 x_min, x_max, y_min, y_max; +}; + +static const struct min_max_quirk min_max_pnpid_table[] = { + { + (const char * const []){"LEN0033", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5052, 2258, 4832 + }, + { + (const char * const []){"LEN0042", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1232, 5710, 1156, 4696 + }, + { + (const char * const []){"LEN0034", "LEN0036", "LEN0037", + "LEN0039", "LEN2002", "LEN2004", + NULL}, + {ANY_BOARD_ID, 2961}, + 1024, 5112, 2024, 4832 + }, + { + (const char * const []){"LEN2000", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5113, 2021, 4832 + }, + { + (const char * const []){"LEN2001", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5022, 2508, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {2691, 2691}, + 1024, 5045, 2457, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1264, 5675, 1171, 4688 + }, + { } +}; + +/* This list has been kindly provided by Synaptics. */ +static const char * const forcepad_pnp_ids[] = { + "SYN300D", + "SYN3014", + NULL +}; + +/***************************************************************************** + * Synaptics communications functions + ****************************************************************************/ + +/* + * Synaptics touchpads report the y coordinate from bottom to top, which is + * opposite from what userspace expects. + * This function is used to invert y before reporting. + */ +static int synaptics_invert_y(int y) +{ + return YMAX_NOMINAL + YMIN_NOMINAL - y; +} + /* * Apply quirk(s) if the hardware matches */ - static void synaptics_apply_quirks(struct psmouse *psmouse, struct synaptics_device_info *info) { @@ -494,38 +547,6 @@ static void synaptics_apply_quirks(struct psmouse *psmouse, } } -static int synaptics_query_hardware(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - int error; - - error = synaptics_identify(psmouse, info); - if (error) - return error; - - error = synaptics_model_id(psmouse, info); - if (error) - return error; - - error = synaptics_firmware_id(psmouse, info); - if (error) - return error; - - error = synaptics_query_modes(psmouse, info); - if (error) - return error; - - error = synaptics_capability(psmouse, info); - if (error) - return error; - - error = synaptics_resolution(psmouse, info); - if (error) - return error; - - return 0; -} - static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { static unsigned char param = 0xc8; @@ -1335,6 +1356,12 @@ static void synaptics_disconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; + /* + * We might have left a breadcrumb when trying to + * set up SMbus companion. + */ + psmouse_smbus_cleanup(psmouse); + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) device_remove_file(&psmouse->ps2dev.serio->dev, @@ -1475,39 +1502,20 @@ void __init synaptics_module_init(void) cr48_profile_sensor = dmi_check_system(cr48_dmi_table); } -static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +static int synaptics_init_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool absolute_mode) { struct synaptics_data *priv; - struct synaptics_device_info *info; - int err = -1; + int err; - /* - * The OLPC XO has issues with Synaptics' absolute mode; the constant - * packet spew overloads the EC such that key presses on the keyboard - * are missed. Given that, don't even attempt to use Absolute mode. - * Relative mode seems to work just fine. - */ - if (absolute_mode && broken_olpc_ec) { - psmouse_info(psmouse, - "OLPC XO detected, not enabling Synaptics protocol.\n"); - return -ENODEV; - } + synaptics_apply_quirks(psmouse, info); psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); if (!priv) return -ENOMEM; - info = &priv->info; - - psmouse_reset(psmouse); - - if (synaptics_query_hardware(psmouse, info)) { - psmouse_err(psmouse, "Unable to query device.\n"); - goto init_fail; - } - - synaptics_apply_quirks(psmouse, info); - + priv->info = *info; priv->absolute_mode = absolute_mode; if (SYN_ID_DISGEST_SUPPORTED(info->identity)) priv->disable_gesture = true; @@ -1518,7 +1526,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) */ priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids); - if (synaptics_set_mode(psmouse)) { + err = synaptics_set_mode(psmouse); + if (err) { psmouse_err(psmouse, "Unable to initialize device.\n"); goto init_fail; } @@ -1595,7 +1604,23 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) return err; } -int synaptics_init(struct psmouse *psmouse) +static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + return synaptics_init_ps2(psmouse, &info, absolute_mode); +} + +int synaptics_init_absolute(struct psmouse *psmouse) { return __synaptics_init(psmouse, true); } @@ -1605,15 +1630,204 @@ int synaptics_init_relative(struct psmouse *psmouse) return __synaptics_init(psmouse, false); } +static int synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + bool absolute_mode = true; + int error; + + /* + * The OLPC XO has issues with Synaptics' absolute mode; the constant + * packet spew overloads the EC such that key presses on the keyboard + * are missed. Given that, don't even attempt to use Absolute mode. + * Relative mode seems to work just fine. + */ + if (broken_olpc_ec) { + psmouse_info(psmouse, + "OLPC XO detected, forcing relative protocol.\n"); + absolute_mode = false; + } + + error = synaptics_init_ps2(psmouse, info, absolute_mode); + if (error) + return error; + + return absolute_mode ? PSMOUSE_SYNAPTICS : PSMOUSE_SYNAPTICS_RELATIVE; +} + #else /* CONFIG_MOUSE_PS2_SYNAPTICS */ void __init synaptics_module_init(void) { } -int synaptics_init(struct psmouse *psmouse) +static int __maybe_unused +synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) { return -ENOSYS; } #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + +/* + * The newest Synaptics device can use a secondary bus (called InterTouch) which + * provides a better bandwidth and allow a better control of the touchpads. + * This is used to decide if we need to use this bus or not. + */ +enum { + SYNAPTICS_INTERTOUCH_NOT_SET = -1, + SYNAPTICS_INTERTOUCH_OFF, + SYNAPTICS_INTERTOUCH_ON, +}; + +static int synaptics_intertouch = SYNAPTICS_INTERTOUCH_NOT_SET; +module_param_named(synaptics_intertouch, synaptics_intertouch, int, 0644); +MODULE_PARM_DESC(synaptics_intertouch, "Use a secondary bus for the Synaptics device."); + +static int synaptics_create_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + bool topbuttonpad = + psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10); + const struct rmi_device_platform_data pdata = { + .sensor_pdata = { + .sensor_type = rmi_sensor_touchpad, + .axis_align.flip_y = true, + /* to prevent cursors jumps: */ + .kernel_tracking = true, + .topbuttonpad = topbuttonpad, + }, + .f30_data = { + .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c), + .trackstick_buttons = + !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10), + }, + }; + const struct i2c_board_info intertouch_board = { + I2C_BOARD_INFO("rmi4_smbus", 0x2c), + .flags = I2C_CLIENT_HOST_NOTIFY, + }; + + return psmouse_smbus_init(psmouse, &intertouch_board, + &pdata, sizeof(pdata), + leave_breadcrumbs); +} + +/** + * synaptics_setup_intertouch - called once the PS/2 devices are enumerated + * and decides to instantiate a SMBus InterTouch device. + */ +static int synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + int error; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_OFF) + return -ENXIO; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_NOT_SET) { + if (!psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !psmouse_matches_pnp_id(psmouse, smbus_pnp_ids)) + return -ENXIO; + } + + psmouse_info(psmouse, "Trying to set up SMBus access\n"); + + error = synaptics_create_intertouch(psmouse, info, leave_breadcrumbs); + if (error) { + if (error == -EAGAIN) + psmouse_info(psmouse, "SMbus companion is not ready yet\n"); + else + psmouse_err(psmouse, "unable to create intertouch device\n"); + + return error; + } + + return 0; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (!SYN_CAP_INTERTOUCH(info.ext_cap_0c)) + return -ENXIO; + + return synaptics_create_intertouch(psmouse, &info, false); +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +static int __maybe_unused +synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + return -ENOSYS; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) + +int synaptics_init(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + int retval; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (SYN_CAP_INTERTOUCH(info.ext_cap_0c)) { + error = synaptics_setup_intertouch(psmouse, &info, true); + if (!error) + return PSMOUSE_SYNAPTICS_SMBUS; + } + + retval = synaptics_setup_ps2(psmouse, &info); + if (retval < 0) { + /* + * Not using any flavor of Synaptics support, so clean up + * SMbus breadcrumbs, if any. + */ + psmouse_smbus_cleanup(psmouse); + } + + return retval; +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +int synaptics_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index d9b824fbddc2..31652d98b8f7 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -90,6 +90,7 @@ #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) #define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) #define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) +#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & 0x004000) /* * The following descibes response for the 0x10 query. @@ -204,8 +205,10 @@ struct synaptics_data { void synaptics_module_init(void); int synaptics_detect(struct psmouse *psmouse, bool set_properties); -int synaptics_init(struct psmouse *psmouse); +int synaptics_init_absolute(struct psmouse *psmouse); int synaptics_init_relative(struct psmouse *psmouse); +int synaptics_init_smbus(struct psmouse *psmouse); +int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); #endif /* _SYNAPTICS_H */ -- cgit From f5a28a7d4858f94a2d8b5271ffee607de30050e4 Mon Sep 17 00:00:00 2001 From: David Jander Date: Mon, 20 Mar 2017 11:05:29 -0700 Subject: Input: ads7846 - avoid pen up/down when reading hwmon Each time the HWMON devices are read (e.g. battery voltage) while the touchscreen is held pressed, extra pen-up and pen-down events are generated. This is fixed by avoiding the UP event when the touchscreen is stopped. Signed-off-by: David Jander Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f5793e3d945f..735a0be1ad95 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -871,7 +871,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) msecs_to_jiffies(TS_POLL_PERIOD)); } - if (ts->pendown) { + if (ts->pendown && !ts->stopped) { struct input_dev *input = ts->input; input_report_key(input, BTN_TOUCH, 0); -- cgit From 4896fb1348713344abbd9f692b393b5fdc539bf8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 16:50:28 -0700 Subject: Input: melfas_mip4 - ensure that device is present Try a quick read from the device in mip4_query_device() to make sure that the device is there, as we do not consider failures to retrieve product name or resolution fatal. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 703d7f983d0a..05108c2fea93 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -253,10 +253,21 @@ static int mip4_get_fw_version(struct mip4_ts *ts) */ static int mip4_query_device(struct mip4_ts *ts) { + union i2c_smbus_data dummy; int error; u8 cmd[2]; u8 buf[14]; + /* + * Make sure there is something at this address as we do not + * consider subsequent failures as fatal. + */ + if (i2c_smbus_xfer(ts->client->adapter, ts->client->addr, + 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&ts->client->dev, "nothing at this address\n"); + return -ENXIO; + } + /* Product name */ cmd[0] = MIP4_R0_INFO; cmd[1] = MIP4_R1_INFO_PRODUCT_NAME; -- cgit From aa0e26bb786b00eaa897e024769e299470815efe Mon Sep 17 00:00:00 2001 From: David Rivshin Date: Wed, 29 Mar 2017 00:14:16 -0700 Subject: Input: matrix_keypad - add option to drive inactive columns The gpio-matrix-keypad driver normally sets inactive columns as inputs while scanning. This does not work for all hardware, which may require the inactive columns to be actively driven in order to overcome any pull-ups/downs on the columns. Signed-off-by: David Rivshin Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 18839cd5f76e..1f316d66e6f7 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -42,9 +42,10 @@ struct matrix_keypad { }; /* - * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause - * minmal side effect when scanning other columns, here it is configured to - * be input, and it should work on most platforms. + * NOTE: If drive_inactive_cols is false, then the GPIO has to be put into + * HiZ when de-activated to cause minmal side effect when scanning other + * columns. In that case it is configured here to be input, otherwise it is + * driven with the inactive value. */ static void __activate_col(const struct matrix_keypad_platform_data *pdata, int col, bool on) @@ -55,7 +56,8 @@ static void __activate_col(const struct matrix_keypad_platform_data *pdata, gpio_direction_output(pdata->col_gpios[col], level_on); } else { gpio_set_value_cansleep(pdata->col_gpios[col], !level_on); - gpio_direction_input(pdata->col_gpios[col]); + if (!pdata->drive_inactive_cols) + gpio_direction_input(pdata->col_gpios[col]); } } @@ -432,6 +434,9 @@ matrix_keypad_parse_dt(struct device *dev) if (of_get_property(np, "gpio-activelow", NULL)) pdata->active_low = true; + pdata->drive_inactive_cols = + of_property_read_bool(np, "drive-inactive-cols"); + of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms); of_property_read_u32(np, "col-scan-delay-us", &pdata->col_scan_delay_us); -- cgit From 00480324d1cc6679f001ad2b2b300b3936ac04f1 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Wed, 29 Mar 2017 00:16:35 -0700 Subject: Input: max11801_ts - add missing of_match_table Added missing of_match_table for max11801_ts driver with compatible as "maxim,max11801_ts" Signed-off-by: Jagan Teki Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/max11801_ts.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index a595ae5284e3..72ca3efb5781 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -224,9 +224,16 @@ static const struct i2c_device_id max11801_ts_id[] = { }; MODULE_DEVICE_TABLE(i2c, max11801_ts_id); +static const struct of_device_id max11801_ts_dt_ids[] = { + { .compatible = "maxim,max11801" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids); + static struct i2c_driver max11801_ts_driver = { .driver = { .name = "max11801_ts", + .of_match_table = max11801_ts_dt_ids, }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, -- cgit From 00a06c22e9fc0a33ae0b6ca2d47938340dbcd539 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 4 Mar 2017 11:29:34 -0800 Subject: i2c: export i2c_client_type structure i2c bus has 2 different types of device belonging to the same bus and bus notifiers use device type to distinguish between adapters and clients. Previously we only had i2c_adapter_type exported, which made code wanting to work with i2c_client devices test for type not equal to adapter type. This unfortunately is not safe if we ever add another type to the bus, so let's export i2c_client_type as well. Reviewed-by: Jean Delvare Acked-by: Benjamin Tissoires Reviewed-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d2402bbf6729..bf7892e3b0c8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -74,7 +74,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -static struct device_type i2c_client_type; static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; @@ -1097,11 +1096,12 @@ struct bus_type i2c_bus_type = { }; EXPORT_SYMBOL_GPL(i2c_bus_type); -static struct device_type i2c_client_type = { +struct device_type i2c_client_type = { .groups = i2c_dev_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, }; +EXPORT_SYMBOL_GPL(i2c_client_type); /** -- cgit From 0daaf99d8424f12cdf87e00c435c9cb93667f519 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 27 Feb 2017 20:09:09 -0800 Subject: i2c: copy device properties when using i2c_register_board_info() This will allow marking device property lists as __initdata, the same as board info structures themselves. Reviewed-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-boardinfo.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 6e5fac6a5262..0e285c68b2ff 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); * * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. + * Device properties are deep-copied though. */ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { @@ -78,6 +80,16 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig devinfo->busnum = busnum; devinfo->board_info = *info; + + if (info->properties) { + devinfo->board_info.properties = + property_entries_dup(info->properties); + if (IS_ERR(devinfo->board_info.properties)) { + status = PTR_ERR(devinfo->board_info.properties); + break; + } + } + list_add_tail(&devinfo->list, &__i2c_board_list); } -- cgit From 4124c4eba40256b65acb5016a1edfdd59a1960b6 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 1 Mar 2017 11:45:51 -0800 Subject: i2c: allow attaching IRQ resources to i2c_board_info Simple integer for interrupt number is not expressive enough, as it does not convey interrupt trigger type that should be used. Let's allow attaching array of resources to the board info and have i2c core parse first IRQ resource and set up interrupt trigger as needed. Reviewed-by: Wolfram Sang Signed-off-by: Dmitry Torokhov --- drivers/i2c/i2c-boardinfo.c | 12 ++++++++++++ drivers/i2c/i2c-core.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 0e285c68b2ff..31186ead5a40 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -90,6 +90,18 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig } } + if (info->resources) { + devinfo->board_info.resources = + kmemdup(info->resources, + info->num_resources * + sizeof(*info->resources), + GFP_KERNEL); + if (!devinfo->board_info.resources) { + status = -ENOMEM; + break; + } + } + list_add_tail(&devinfo->list, &__i2c_board_list); } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index bf7892e3b0c8..679a31fcb6d6 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1278,6 +1278,32 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, i2c_encode_flags_to_addr(client)); } +static int i2c_dev_irq_from_resources(const struct resource *resources, + unsigned int num_resources) +{ + struct irq_data *irqd; + int i; + + for (i = 0; i < num_resources; i++) { + const struct resource *r = &resources[i]; + + if (resource_type(r) != IORESOURCE_IRQ) + continue; + + if (r->flags & IORESOURCE_BITS) { + irqd = irq_get_irq_data(r->start); + if (!irqd) + break; + + irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); + } + + return r->start; + } + + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -1313,7 +1339,11 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->flags = info->flags; client->addr = info->addr; + client->irq = info->irq; + if (!client->irq) + client->irq = i2c_dev_irq_from_resources(info->resources, + info->num_resources); strlcpy(client->name, info->type, sizeof(client->name)); -- cgit From f069b5a0b27ad4a87e9351e54fbcab3d3f8a9fd5 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Sat, 1 Apr 2017 09:43:47 -0700 Subject: Input: bma150 - remove support for bma150 This essentially reverts commit baf28d91e7b1 ("Input: bma150 - avoid binding to bma180 if IIO bma180 driver present") and commit ef3714fdbc8d ("Input: bma150 - extend chip detection for bma180") Rationale: initially (2012) the GTA04 device using a bma180 chip simply referenced the bma150 platform driver in its board file [1] which happened to work in all scenarios that were tested. When conversion to DT started (2014), we needed to make the driver be still recognised. Hence we introduced the compatibility to the bma180 chip in Linux 3.15-rc5 [2] without further checks if it is really 100% compatible. This worked flawlessly for years with the GTA04 device. Recently (2016), Hans de Goede pointed out that the chips are not as similar as they appeared and the driver works with the bma180 for the GTA04 only by good luck. He proposed to remove the bma180 support completely [3], but we still did need it until we have a replacement. Thus, a conditional compile was added. We have now developed a generic iio-input-bridge which works with any 2 or 3 axis iio based accelerometer. It has been tested on GTA04 and Pyra and works as expected. Therefore we can remove the bma180 support from this driver completely. User-space API compatibility can be restored by using the iio-input-bridge. Maybe it is time to convert the bma150 driver to iio as well and retire the accelerometer input drivers completely but this is a different story and task. [1]: https://github.com/neilbrown/linux/blob/gta04/3.2.y/arch/arm/mach-omap2/board-omap3gta04.c#L976 [2]: https://patchwork.kernel.org/patch/3961171/ [3]: https://patchwork.kernel.org/patch/9325481/ Signed-off-by: H. Nikolaus Schaller Reviewed-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/bma150.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 1fa85379f86c..1efcfdf9f8a8 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -70,7 +70,6 @@ #define BMA150_CFG_5_REG 0x11 #define BMA150_CHIP_ID 2 -#define BMA180_CHIP_ID 3 #define BMA150_CHIP_ID_REG BMA150_DATA_0_REG #define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG @@ -538,13 +537,8 @@ static int bma150_probe(struct i2c_client *client, return -EIO; } - /* - * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail - * the probe for the bma180 as the iio driver is preferred. - */ chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); - if (chip_id != BMA150_CHIP_ID && - (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) { + if (chip_id != BMA150_CHIP_ID) { dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id); return -EINVAL; } @@ -648,9 +642,6 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); static const struct i2c_device_id bma150_id[] = { { "bma150", 0 }, -#if !IS_ENABLED(CONFIG_BMA180) - { "bma180", 0 }, -#endif { "smb380", 0 }, { "bma023", 0 }, { } -- cgit From f6f08c55cced6885f1e1448cd0806098e836c5f5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 1 Apr 2017 11:33:11 -0700 Subject: Input: psmouse - fix cleaning up SMBus companions When trying to destroy platform data after destruction of SMbus companion, we need to make sure that we are actually dealing with an SMB companion device, and not some random I2C client device. Fixes: 8eb92e5c9133 ("Input: psmouse - add support for SMBus companions") Reported-by: Benjamin Tissoires Tested-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-smbus.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 061c1cc44aef..d2b1ea34feac 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -61,24 +61,29 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) { - struct psmouse_smbus_dev *smbdev; + struct psmouse_smbus_dev *smbdev, *tmp; mutex_lock(&psmouse_smbus_mutex); - list_for_each_entry(smbdev, &psmouse_smbus_list, node) { - if (smbdev->client == client) { + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (smbdev->client != client) + continue; + + kfree(client->dev.platform_data); + client->dev.platform_data = NULL; + + if (!smbdev->dead) { psmouse_dbg(smbdev->psmouse, "Marking SMBus companion %s as gone\n", dev_name(&smbdev->client->dev)); - smbdev->client = NULL; smbdev->dead = true; serio_rescan(smbdev->psmouse->ps2dev.serio); + } else { + list_del(&smbdev->node); + kfree(smbdev); } } - kfree(client->dev.platform_data); - client->dev.platform_data = NULL; - mutex_unlock(&psmouse_smbus_mutex); } @@ -162,17 +167,20 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse) struct psmouse_smbus_dev *smbdev = psmouse->private; mutex_lock(&psmouse_smbus_mutex); - list_del(&smbdev->node); - mutex_unlock(&psmouse_smbus_mutex); - if (smbdev->client) { + if (smbdev->dead) { + list_del(&smbdev->node); + kfree(smbdev); + } else { + smbdev->dead = true; psmouse_dbg(smbdev->psmouse, "posting removal request for SMBus companion %s\n", dev_name(&smbdev->client->dev)); psmouse_smbus_schedule_remove(smbdev->client); } - kfree(smbdev); + mutex_unlock(&psmouse_smbus_mutex); + psmouse->private = NULL; } -- cgit From e6eba3fac9a0eb2018a85505b91740e27c60fdba Mon Sep 17 00:00:00 2001 From: Rajat Jain Date: Mon, 3 Apr 2017 11:53:41 -0700 Subject: Input: cros_ec_keyb - add an EC event for sysrq Some form factors (detachables/tablets) may not have a keyboard and thus user may have to resort to using a defined EC UI to send sysrq(s) to the kernel in order to collect crash info etc. This UI typically is in the form of user pressing volume / power buttons in some specific sequence and for some specific time. Add a new EC event that allows EC to communicate the sysrq to the AP. (We're skipping event number 5 because it has been reserved for something else) Signed-off-by: Rajat Jain Acked-by: Lee Jones Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/cros_ec_keyb.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 6a250d65f8fe..c7a8120b13c0 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -260,6 +261,12 @@ static int cros_ec_keyb_work(struct notifier_block *nb, ckdev->ec->event_size); break; + case EC_MKBP_EVENT_SYSRQ: + val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq); + dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val); + handle_sysrq(val); + break; + case EC_MKBP_EVENT_BUTTON: case EC_MKBP_EVENT_SWITCH: /* -- cgit From a716a026bb0d824c9ab6d6ac778c030c0030b178 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 25 Mar 2017 10:45:13 -0700 Subject: Input: psmouse - use i2c_client_type to locate i2c clients Now that i2c_client_type structure is exported, we can use it, instead of i2c_adapter_type, when looking for devices that are i2c clients. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-smbus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index d2b1ea34feac..c7ac24d119c1 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -99,7 +99,7 @@ static int psmouse_smbus_notifier_call(struct notifier_block *nb, break; case BUS_NOTIFY_REMOVED_DEVICE: - if (dev->type != &i2c_adapter_type) + if (dev->type == &i2c_client_type) psmouse_smbus_detach_i2c_client(to_i2c_client(dev)); break; } -- cgit From 2c6ecbba90d4e909bdc8982b4a2318e99d7fc4f2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 17:40:57 -0700 Subject: Input: synaptics - add synaptics_query_int() Factor out querying and parsing 3-byte response into an integer value. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 77 ++++++++++++++++------------------------- drivers/input/mouse/synaptics.h | 3 +- 2 files changed, 32 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index d494c6c6aadc..da9ca356a7e3 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -190,6 +190,22 @@ static int synaptics_send_cmd(struct psmouse *psmouse, return 0; } +static int synaptics_query_int(struct psmouse *psmouse, u8 query_cmd, u32 *val) +{ + int error; + union { + __be32 be_val; + char buf[4]; + } resp = { 0 }; + + error = synaptics_send_cmd(psmouse, query_cmd, resp.buf + 1); + if (error) + return error; + + *val = be32_to_cpu(resp.be_val); + return 0; +} + /* * Identify Touchpad * See also the SYN_ID_* macros @@ -197,14 +213,12 @@ static int synaptics_send_cmd(struct psmouse *psmouse, static int synaptics_identify(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char id[3]; int error; - error = synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id); + error = synaptics_query_int(psmouse, SYN_QUE_IDENTIFY, &info->identity); if (error) return error; - info->identity = (id[0] << 16) | (id[1] << 8) | id[2]; return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } @@ -215,15 +229,7 @@ static int synaptics_identify(struct psmouse *psmouse, static int synaptics_model_id(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char mi[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi); - if (error) - return error; - - info->model_id = (mi[0] << 16) | (mi[1] << 8) | mi[2]; - return 0; + return synaptics_query_int(psmouse, SYN_QUE_MODEL, &info->model_id); } /* @@ -232,29 +238,8 @@ static int synaptics_model_id(struct psmouse *psmouse, static int synaptics_firmware_id(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char fwid[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid); - if (error) - return error; - - info->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; - return 0; -} - -static int synaptics_more_extended_queries(struct psmouse *psmouse, - struct synaptics_device_info *info) -{ - unsigned char buf[3]; - int error; - - error = synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf); - if (error) - return error; - - info->ext_cap_10 = (buf[0] << 16) | (buf[1] << 8) | buf[2]; - return 0; + return synaptics_query_int(psmouse, SYN_QUE_FIRMWARE_ID, + &info->firmware_id); } /* @@ -278,7 +263,8 @@ static int synaptics_query_modes(struct psmouse *psmouse, info->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse, info); + return synaptics_query_int(psmouse, SYN_QUE_MEXT_CAPAB_10, + &info->ext_cap_10); return 0; } @@ -290,14 +276,13 @@ static int synaptics_query_modes(struct psmouse *psmouse, static int synaptics_capability(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char cap[3]; int error; - error = synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap); + error = synaptics_query_int(psmouse, SYN_QUE_CAPABILITIES, + &info->capabilities); if (error) return error; - info->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; info->ext_cap = info->ext_cap_0c = 0; /* @@ -315,29 +300,27 @@ static int synaptics_capability(struct psmouse *psmouse, info->capabilities = 0; if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB, + &info->ext_cap); + if (error) { psmouse_warn(psmouse, "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { - info->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8) - info->ext_cap &= 0xff0fff; + info->ext_cap &= ~SYN_CAP_MB_MASK; } } if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) { - error = synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap); + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB_0C, + &info->ext_cap_0c); if (error) psmouse_warn(psmouse, "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - else - info->ext_cap_0c = - (cap[0] << 16) | (cap[1] << 8) | cap[2]; } return 0; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 31652d98b8f7..87fbe5b53803 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -52,7 +52,8 @@ #define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) #define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) -#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) +#define SYN_CAP_MB_MASK GENMASK(15, 12) +#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & SYN_CAP_MB_MASK) >> 12) #define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) #define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) -- cgit From 991d29fe02a767d13275b38d774cf7c35a4f4a44 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 14:56:06 -0700 Subject: Input: synaptics - use BIT() and GENMASK() macros Use standard infrastructure, such as BIT and GENMASK, instead of rolling bitmasks by hand. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 6 +-- drivers/input/mouse/synaptics.h | 90 ++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index da9ca356a7e3..26f4520f1903 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -905,9 +905,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) { for (i = 0; i < ext_bits; i++) { input_report_key(dev, BTN_0 + 2 * i, - hw->ext_buttons & (1 << i)); + hw->ext_buttons & BIT(i)); input_report_key(dev, BTN_1 + 2 * i, - hw->ext_buttons & (1 << (i + ext_bits))); + hw->ext_buttons & BIT(i + ext_bits)); } return; } @@ -1519,7 +1519,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse, SYN_NEWABS : SYN_OLDABS; psmouse_info(psmouse, - "Touchpad model: %u, fw: %u.%u, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", + "Touchpad model: %lu, fw: %lu.%lu, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", SYN_ID_MODEL(info->identity), SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity), info->model_id, diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 87fbe5b53803..7a998fbfa6b0 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -25,37 +25,37 @@ #define SYN_QUE_MEXT_CAPAB_10 0x10 /* synatics modes */ -#define SYN_BIT_ABSOLUTE_MODE (1 << 7) -#define SYN_BIT_HIGH_RATE (1 << 6) -#define SYN_BIT_SLEEP_MODE (1 << 3) -#define SYN_BIT_DISABLE_GESTURE (1 << 2) -#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1) -#define SYN_BIT_W_MODE (1 << 0) +#define SYN_BIT_ABSOLUTE_MODE BIT(7) +#define SYN_BIT_HIGH_RATE BIT(6) +#define SYN_BIT_SLEEP_MODE BIT(3) +#define SYN_BIT_DISABLE_GESTURE BIT(2) +#define SYN_BIT_FOUR_BYTE_CLIENT BIT(1) +#define SYN_BIT_W_MODE BIT(0) /* synaptics model ID bits */ -#define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) -#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) -#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) -#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) -#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) -#define SYN_MODEL_PEN(m) ((m) & (1 << 6)) -#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) -#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) +#define SYN_MODEL_ROT180(m) ((m) & BIT(23)) +#define SYN_MODEL_PORTRAIT(m) ((m) & BIT(22)) +#define SYN_MODEL_SENSOR(m) (((m) & GENMASK(21, 16)) >> 16) +#define SYN_MODEL_HARDWARE(m) (((m) & GENMASK(15, 9)) >> 9) +#define SYN_MODEL_NEWABS(m) ((m) & BIT(7)) +#define SYN_MODEL_PEN(m) ((m) & BIT(6)) +#define SYN_MODEL_SIMPLIC(m) ((m) & BIT(5)) +#define SYN_MODEL_GEOMETRY(m) ((m) & GENMASK(3, 0)) /* synaptics capability bits */ -#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) -#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) -#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) -#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) -#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) -#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) -#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) -#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) -#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) +#define SYN_CAP_EXTENDED(c) ((c) & BIT(23)) +#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & BIT(18)) +#define SYN_CAP_PASS_THROUGH(c) ((c) & BIT(7)) +#define SYN_CAP_SLEEP(c) ((c) & BIT(4)) +#define SYN_CAP_FOUR_BUTTON(c) ((c) & BIT(3)) +#define SYN_CAP_MULTIFINGER(c) ((c) & BIT(1)) +#define SYN_CAP_PALMDETECT(c) ((c) & BIT(0)) +#define SYN_CAP_SUBMODEL_ID(c) (((c) & GENMASK(15, 8)) >> 8) +#define SYN_EXT_CAP_REQUESTS(c) (((c) & GENMASK(22, 20)) >> 20) #define SYN_CAP_MB_MASK GENMASK(15, 12) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & SYN_CAP_MB_MASK) >> 12) -#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & GENMASK(23, 16)) >> 16) +#define SYN_MEXT_CAP_BIT(m) ((m) & BIT(1)) /* * The following describes response for the 0x0c query. @@ -84,14 +84,14 @@ * hinged at the top. * 2 0x20 report min query 0x0f gives min coord reported */ -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ -#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ -#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) -#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) -#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) -#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) -#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) -#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & 0x004000) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & BIT(20)) /* 1-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & BIT(8)) /* 2-button ClickPad */ +#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & BIT(17)) +#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & BIT(13)) +#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & BIT(19)) +#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & BIT(10)) +#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & BIT(11)) +#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & BIT(14)) /* * The following descibes response for the 0x10 query. @@ -110,27 +110,27 @@ * 3 0xff SecurePad height the height of the SecurePad fingerprint * reader. */ -#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) -#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) +#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & BIT(16)) +#define SYN_CAP_SECUREPAD(ex10) ((ex10) & BIT(17)) #define SYN_EXT_BUTTON_STICK_L(eb) (((eb) & BIT(0)) >> 0) #define SYN_EXT_BUTTON_STICK_M(eb) (((eb) & BIT(1)) >> 1) #define SYN_EXT_BUTTON_STICK_R(eb) (((eb) & BIT(2)) >> 2) /* synaptics modes query bits */ -#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -#define SYN_MODE_RATE(m) ((m) & (1 << 6)) -#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) -#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) -#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) -#define SYN_MODE_WMODE(m) ((m) & (1 << 0)) +#define SYN_MODE_ABSOLUTE(m) ((m) & BIT(7)) +#define SYN_MODE_RATE(m) ((m) & BIT(6)) +#define SYN_MODE_BAUD_SLEEP(m) ((m) & BIT(3)) +#define SYN_MODE_DISABLE_GESTURE(m) ((m) & BIT(2)) +#define SYN_MODE_PACKSIZE(m) ((m) & BIT(1)) +#define SYN_MODE_WMODE(m) ((m) & BIT(0)) /* synaptics identify query bits */ -#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) -#define SYN_ID_MAJOR(i) ((i) & 0x0f) -#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_MODEL(i) (((i) & GENMASK(7, 4)) >> 4) +#define SYN_ID_MAJOR(i) (((i) & GENMASK(3, 0)) >> 0) +#define SYN_ID_MINOR(i) (((i) & GENMASK(23, 16)) >> 16) #define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) -#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) +#define SYN_ID_IS_SYNAPTICS(i) (((i) & GENMASK(15, 8)) == 0x004700U) #define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4) /* synaptics special commands */ -- cgit From 212baf03a30a8fb29ab5f69726bb920ebe3d44a1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Mar 2017 18:38:14 -0700 Subject: Input: synaptics - do not abuse -1 as return value Let's stop using -1 as a universal return value and instead propagate errors from underlying calls up the stack. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 71 ++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 26f4520f1903..81ec4590003e 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -82,12 +82,17 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) { unsigned char param[1]; + int error; + + error = psmouse_sliced_command(psmouse, mode); + if (error) + return error; - if (psmouse_sliced_command(psmouse, mode)) - return -1; param[0] = SYN_PS_SET_MODE2; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE); + if (error) + return error; + return 0; } @@ -534,16 +539,19 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { static unsigned char param = 0xc8; struct synaptics_data *priv = psmouse->private; + int error; if (!(SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c))) return 0; - if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) - return -1; + error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL); + if (error) + return error; - if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE); + if (error) + return error; /* Advanced gesture mode also sends multi finger data */ priv->info.capabilities |= BIT(1); @@ -554,6 +562,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static int synaptics_set_mode(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; + int error; priv->mode = 0; if (priv->absolute_mode) @@ -565,13 +574,18 @@ static int synaptics_set_mode(struct psmouse *psmouse) if (SYN_CAP_EXTENDED(priv->info.capabilities)) priv->mode |= SYN_BIT_W_MODE; - if (synaptics_mode_cmd(psmouse, priv->mode)) - return -1; + error = synaptics_mode_cmd(psmouse, priv->mode); + if (error) + return error; - if (priv->absolute_mode && - synaptics_set_advanced_gesture_mode(psmouse)) { - psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); - return -1; + if (priv->absolute_mode) { + error = synaptics_set_advanced_gesture_mode(psmouse); + if (error) { + psmouse_err(psmouse, + "Advanced gesture mode init failed: %d\n", + error); + return error; + } } return 0; @@ -598,12 +612,17 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) static int synaptics_pt_write(struct serio *serio, unsigned char c) { struct psmouse *parent = serio_get_drvdata(serio->parent); - char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + int error; + + error = psmouse_sliced_command(parent, c); + if (error) + return error; + + error = ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE); + if (error) + return error; - if (psmouse_sliced_command(parent, c)) - return -1; - if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) - return -1; return 0; } @@ -1380,19 +1399,21 @@ static int synaptics_reconnect(struct psmouse *psmouse) } while (error && ++retry < 3); if (error) - return -1; + return error; if (retry > 1) psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - if (synaptics_query_hardware(psmouse, &info)) { + error = synaptics_query_hardware(psmouse, &info); + if (error) { psmouse_err(psmouse, "Unable to query device.\n"); - return -1; + return error; } - if (synaptics_set_mode(psmouse)) { + error = synaptics_set_mode(psmouse); + if (error) { psmouse_err(psmouse, "Unable to initialize device.\n"); - return -1; + return error; } if (info.identity != priv->info.identity || @@ -1405,7 +1426,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) priv->info.model_id, info.model_id, priv->info.capabilities, info.capabilities, priv->info.ext_cap, info.ext_cap); - return -1; + return -ENXIO; } return 0; -- cgit From f6c4442bfa0812efbb5d54db01a17a7ba0fc9298 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 11:20:38 -0700 Subject: Input: synaptics - use u8 instead of unsigned char The rest of the kernel uses u8, u16, etc for data coming form hardware, let's switch ti using u8 here as well. Also turn pkt_type into an enum. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 60 ++++++++++++++++++++--------------------- drivers/input/mouse/synaptics.h | 22 ++++++++------- 2 files changed, 42 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 81ec4590003e..131df9d3660f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -79,9 +79,9 @@ /* * Set the synaptics touchpad mode byte by special commands */ -static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) +static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode) { - unsigned char param[1]; + u8 param[1]; int error; error = psmouse_sliced_command(psmouse, mode); @@ -99,7 +99,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) int synaptics_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + u8 param[4]; param[0] = 0; @@ -179,12 +179,11 @@ static const char * const smbus_pnp_ids[] = { /* * Send a command to the synpatics touchpad by special commands */ -static int synaptics_send_cmd(struct psmouse *psmouse, - unsigned char c, unsigned char *param) +static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) { int error; - error = psmouse_sliced_command(psmouse, c); + error = psmouse_sliced_command(psmouse, cmd); if (error) return error; @@ -254,7 +253,7 @@ static int synaptics_firmware_id(struct psmouse *psmouse, static int synaptics_query_modes(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char bid[3]; + u8 bid[3]; int error; /* firmwares prior 7.5 have no board_id encoded */ @@ -338,7 +337,7 @@ static int synaptics_capability(struct psmouse *psmouse, static int synaptics_resolution(struct psmouse *psmouse, struct synaptics_device_info *info) { - unsigned char resp[3]; + u8 resp[3]; int error; if (SYN_ID_MAJOR(info->identity) < 4) @@ -537,7 +536,7 @@ static void synaptics_apply_quirks(struct psmouse *psmouse, static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { - static unsigned char param = 0xc8; + static u8 param = 0xc8; struct synaptics_data *priv = psmouse->private; int error; @@ -609,7 +608,7 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *serio, unsigned char c) +static int synaptics_pt_write(struct serio *serio, u8 c) { struct psmouse *parent = serio_get_drvdata(serio->parent); u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ @@ -648,13 +647,12 @@ static void synaptics_pt_stop(struct serio *serio) serio_continue_rx(parent->ps2dev.serio); } -static int synaptics_is_pt_packet(unsigned char *buf) +static int synaptics_is_pt_packet(u8 *buf) { return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; } -static void synaptics_pass_pt_packet(struct serio *ptport, - unsigned char *packet) +static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) { struct psmouse *child = serio_get_drvdata(ptport); @@ -717,7 +715,7 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_parse_agm(const unsigned char buf[], +static void synaptics_parse_agm(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -744,7 +742,7 @@ static void synaptics_parse_agm(const unsigned char buf[], } } -static void synaptics_parse_ext_buttons(const unsigned char buf[], +static void synaptics_parse_ext_buttons(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -756,7 +754,7 @@ static void synaptics_parse_ext_buttons(const unsigned char buf[], hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; } -static int synaptics_parse_hw_state(const unsigned char buf[], +static int synaptics_parse_hw_state(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -832,7 +830,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) - hw->scroll = (signed char)(buf[1]); + hw->scroll = (s8)buf[1]; } if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { @@ -1134,18 +1132,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_sync(dev); } -static int synaptics_validate_byte(struct psmouse *psmouse, - int idx, unsigned char pkt_type) +static bool synaptics_validate_byte(struct psmouse *psmouse, + int idx, enum synaptics_pkt_type pkt_type) { - static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; - static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - const char *packet = psmouse->packet; + static const u8 newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; + static const u8 newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; + static const u8 oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + const u8 *packet = psmouse->packet; if (idx < 0 || idx > 4) - return 0; + return false; switch (pkt_type) { @@ -1161,19 +1159,21 @@ static int synaptics_validate_byte(struct psmouse *psmouse, default: psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); - return 0; + return false; } } -static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) +static enum synaptics_pkt_type +synaptics_detect_pkt_type(struct psmouse *psmouse) { int i; - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) { if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { psmouse_info(psmouse, "using relaxed packet validation\n"); return SYN_NEWABS_RELAXED; } + } return SYN_NEWABS_STRICT; } @@ -1378,7 +1378,7 @@ static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; struct synaptics_device_info info; - unsigned char param[2]; + u8 param[2]; int retry = 0; int error; diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 7a998fbfa6b0..fc00e005c611 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -137,15 +137,17 @@ #define SYN_PS_SET_MODE2 0x14 #define SYN_PS_CLIENT_CMD 0x28 -/* synaptics packet types */ -#define SYN_NEWABS 0 -#define SYN_NEWABS_STRICT 1 -#define SYN_NEWABS_RELAXED 2 -#define SYN_OLDABS 3 - /* amount to fuzz position data when touchpad reports reduced filtering */ #define SYN_REDUCED_FILTER_FUZZ 8 +/* synaptics packet types */ +enum synaptics_pkt_type { + SYN_NEWABS, + SYN_NEWABS_STRICT, + SYN_NEWABS_RELAXED, + SYN_OLDABS, +}; + /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -159,8 +161,8 @@ struct synaptics_hw_state { unsigned int middle:1; unsigned int up:1; unsigned int down:1; - unsigned char ext_buttons; - signed char scroll; + u8 ext_buttons; + s8 scroll; }; /* Data read from the touchpad */ @@ -181,8 +183,8 @@ struct synaptics_device_info { struct synaptics_data { struct synaptics_device_info info; - unsigned char pkt_type; /* packet type - old, new, etc */ - unsigned char mode; /* current mode byte */ + enum synaptics_pkt_type pkt_type; /* packet type - old, new, etc */ + u8 mode; /* current mode byte */ int scroll; bool absolute_mode; /* run in Absolute mode */ -- cgit From 8cf0adf2f8c3f9f30ba4f1b79e051993aea158d7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 14:28:28 -0700 Subject: Input: synaptics-rmi4 - fix handling failures from rmi_enable_sensor If rmi_enable_sensor() fails in rmi_driver_probe(), we should not return immediately, but disable IRQs and tear down function list. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index d64fc92858f2..821dc47b6eef 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -1234,16 +1234,21 @@ static int rmi_driver_probe(struct device *dev) if (retval < 0) goto err_destroy_functions; - if (data->f01_container->dev.driver) + if (data->f01_container->dev.driver) { /* Driver already bound, so enable ATTN now. */ - return rmi_enable_sensor(rmi_dev); + retval = rmi_enable_sensor(rmi_dev); + if (retval) + goto err_disable_irq; + } return 0; +err_disable_irq: + rmi_disable_irq(rmi_dev, false); err_destroy_functions: rmi_free_function_list(rmi_dev); err: - return retval < 0 ? retval : 0; + return retval; } static struct rmi_driver rmi_physical_driver = { -- cgit From 2593cd1189a2a38a17c97abcd847f28f8a4617be Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 12:34:20 -0700 Subject: Input: synaptics-rmi4 - fix endianness issue in SMBus transport The mapping table holds address in LE form, so we should convert it to CPU when comparing it. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_smbus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 76752555d809..6bb67baa1b77 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -89,17 +89,17 @@ static int rmi_smb_get_command_code(struct rmi_transport_dev *xport, mutex_lock(&rmi_smb->mappingtable_mutex); for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) { - if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) { + struct mapping_table_entry *entry = &rmi_smb->mapping_table[i]; + + if (le16_to_cpu(entry->rmiaddr) == rmiaddr) { if (isread) { - if (rmi_smb->mapping_table[i].readcount - == bytecount) { + if (entry->readcount == bytecount) { *commandcode = i; retval = 0; goto exit; } } else { - if (rmi_smb->mapping_table[i].flags & - RMI_SMB2_MAP_FLAGS_WE) { + if (entry->flags & RMI_SMB2_MAP_FLAGS_WE) { *commandcode = i; retval = 0; goto exit; -- cgit From 8a7c71ae38844948f1e42b3d85ab59868287e413 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 12:45:35 -0700 Subject: Input: synaptics-rmi4 - cleanup SMbus mapping handling There is no reason to copy structures field-by-filed when we can copy elements at once. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_smbus.c | 43 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 6bb67baa1b77..83b1467bb6bf 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -83,63 +83,56 @@ static int rmi_smb_get_command_code(struct rmi_transport_dev *xport, { struct rmi_smb_xport *rmi_smb = container_of(xport, struct rmi_smb_xport, xport); + struct mapping_table_entry new_map; int i; - int retval; - struct mapping_table_entry mapping_data[1]; + int retval = 0; mutex_lock(&rmi_smb->mappingtable_mutex); + for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) { struct mapping_table_entry *entry = &rmi_smb->mapping_table[i]; if (le16_to_cpu(entry->rmiaddr) == rmiaddr) { if (isread) { - if (entry->readcount == bytecount) { - *commandcode = i; - retval = 0; + if (entry->readcount == bytecount) goto exit; - } } else { if (entry->flags & RMI_SMB2_MAP_FLAGS_WE) { - *commandcode = i; - retval = 0; goto exit; } } } } + i = rmi_smb->table_index; rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE; /* constructs mapping table data entry. 4 bytes each entry */ - memset(mapping_data, 0, sizeof(mapping_data)); - - mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr); - mapping_data[0].readcount = bytecount; - mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; - - retval = smb_block_write(xport, i + 0x80, mapping_data, - sizeof(mapping_data)); + memset(&new_map, 0, sizeof(new_map)); + new_map.rmiaddr = cpu_to_le16(rmiaddr); + new_map.readcount = bytecount; + new_map.flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; + retval = smb_block_write(xport, i + 0x80, &new_map, sizeof(new_map)); if (retval < 0) { /* * if not written to device mapping table * clear the driver mapping table records */ - rmi_smb->mapping_table[i].rmiaddr = 0x0000; - rmi_smb->mapping_table[i].readcount = 0; - rmi_smb->mapping_table[i].flags = 0; - goto exit; + memset(&new_map, 0, sizeof(new_map)); } + /* save to the driver level mapping table */ - rmi_smb->mapping_table[i].rmiaddr = rmiaddr; - rmi_smb->mapping_table[i].readcount = bytecount; - rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; - *commandcode = i; + rmi_smb->mapping_table[i] = new_map; exit: mutex_unlock(&rmi_smb->mappingtable_mutex); - return retval; + if (retval < 0) + return retval; + + *commandcode = i; + return 0; } static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, -- cgit From 54bf08946a4ba0567f6ec063f0e42b276c478bcf Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 24 Mar 2017 14:21:44 -0700 Subject: Input: synaptics-rmi4 - when registering sensors do not call them "drivers" We are not registering drivers, but transport devices (AKA sensors), so let's call them that. Also let's rename "retval" to "error" in probe() functions as the variables are used to store error codes. Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_i2c.c | 51 +++++++++++++++++++++--------------------- drivers/input/rmi4/rmi_smbus.c | 43 +++++++++++++++++------------------ drivers/input/rmi4/rmi_spi.c | 44 +++++++++++++++++++----------------- 3 files changed, 69 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 082306d7c207..e28663ef9e5a 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -204,7 +204,7 @@ static int rmi_i2c_probe(struct i2c_client *client, struct rmi_device_platform_data *client_pdata = dev_get_platdata(&client->dev); struct rmi_i2c_xport *rmi_i2c; - int retval; + int error; rmi_i2c = devm_kzalloc(&client->dev, sizeof(struct rmi_i2c_xport), GFP_KERNEL); @@ -220,30 +220,31 @@ static int rmi_i2c_probe(struct i2c_client *client, rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", dev_name(&client->dev)); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, - "adapter does not support required functionality.\n"); + "adapter does not support required functionality\n"); return -ENODEV; } rmi_i2c->supplies[0].supply = "vdd"; rmi_i2c->supplies[1].supply = "vio"; - retval = devm_regulator_bulk_get(&client->dev, + error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); - if (retval < 0) - return retval; + if (error < 0) + return error; - retval = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), + error = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); - if (retval < 0) - return retval; + if (error < 0) + return error; - retval = devm_add_action_or_reset(&client->dev, + error = devm_add_action_or_reset(&client->dev, rmi_i2c_regulator_bulk_disable, rmi_i2c); - if (retval) - return retval; + if (error) + return error; of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms", &rmi_i2c->startup_delay); @@ -263,26 +264,26 @@ static int rmi_i2c_probe(struct i2c_client *client, * Setting the page to zero will (a) make sure the PSR is in a * known state, and (b) make sure we can talk to the device. */ - retval = rmi_set_page(rmi_i2c, 0); - if (retval) { - dev_err(&client->dev, "Failed to set page select to 0.\n"); - return retval; + error = rmi_set_page(rmi_i2c, 0); + if (error) { + dev_err(&client->dev, "Failed to set page select to 0\n"); + return error; } - retval = rmi_register_transport_device(&rmi_i2c->xport); - if (retval) { - dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n", - client->addr); - return retval; + dev_info(&client->dev, "registering I2C-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_i2c->xport); + if (error) { + dev_err(&client->dev, "failed to register sensor: %d\n", error); + return error; } - retval = devm_add_action_or_reset(&client->dev, + + error = devm_add_action_or_reset(&client->dev, rmi_i2c_unregister_transport, rmi_i2c); - if (retval) - return retval; + if (error) + return error; - dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n", - client->addr); return 0; } diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 83b1467bb6bf..225025a0940c 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -53,6 +53,7 @@ static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb) dev_err(&client->dev, "failed to get SMBus version number!\n"); return retval; } + return retval + 1; } @@ -275,19 +276,24 @@ static int rmi_smb_probe(struct i2c_client *client, { struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev); struct rmi_smb_xport *rmi_smb; - int retval; int smbus_version; + int error; + + if (!pdata) { + dev_err(&client->dev, "no platform data, aborting\n"); + return -ENOMEM; + } if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_HOST_NOTIFY)) { dev_err(&client->dev, - "adapter does not support required functionality.\n"); + "adapter does not support required functionality\n"); return -ENODEV; } if (client->irq <= 0) { - dev_err(&client->dev, "no IRQ provided, giving up.\n"); + dev_err(&client->dev, "no IRQ provided, giving up\n"); return client->irq ? client->irq : -ENODEV; } @@ -296,12 +302,7 @@ static int rmi_smb_probe(struct i2c_client *client, if (!rmi_smb) return -ENOMEM; - if (!pdata) { - dev_err(&client->dev, "no platform data, aborting\n"); - return -ENOMEM; - } - - rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", + rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s\n", dev_name(&client->dev)); rmi_smb->client = client; @@ -314,34 +315,30 @@ static int rmi_smb_probe(struct i2c_client *client, rmi_smb->xport.proto_name = "smb2"; rmi_smb->xport.ops = &rmi_smb_ops; - retval = rmi_smb_get_version(rmi_smb); - if (retval < 0) - return retval; + smbus_version = rmi_smb_get_version(rmi_smb); + if (smbus_version < 0) + return smbus_version; - smbus_version = retval; rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d", smbus_version); if (smbus_version != 2) { - dev_err(&client->dev, "Unrecognized SMB version %d.\n", + dev_err(&client->dev, "Unrecognized SMB version %d\n", smbus_version); return -ENODEV; } i2c_set_clientdata(client, rmi_smb); - retval = rmi_register_transport_device(&rmi_smb->xport); - if (retval) { - dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n", - client->addr); - i2c_set_clientdata(client, NULL); - return retval; + dev_info(&client->dev, "registering SMbus-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_smb->xport); + if (error) { + dev_err(&client->dev, "failed to register sensor: %d\n", error); + return error; } - dev_info(&client->dev, "registered rmi smb driver at %#04x.\n", - client->addr); return 0; - } static int rmi_smb_remove(struct i2c_client *client) diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 69548d7d1f10..d97a85907ed6 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -370,7 +370,7 @@ static int rmi_spi_probe(struct spi_device *spi) struct rmi_spi_xport *rmi_spi; struct rmi_device_platform_data *pdata; struct rmi_device_platform_data *spi_pdata = spi->dev.platform_data; - int retval; + int error; if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) return -EINVAL; @@ -383,9 +383,9 @@ static int rmi_spi_probe(struct spi_device *spi) pdata = &rmi_spi->xport.pdata; if (spi->dev.of_node) { - retval = rmi_spi_of_probe(spi, pdata); - if (retval) - return retval; + error = rmi_spi_of_probe(spi, pdata); + if (error) + return error; } else if (spi_pdata) { *pdata = *spi_pdata; } @@ -396,10 +396,10 @@ static int rmi_spi_probe(struct spi_device *spi) if (pdata->spi_data.mode) spi->mode = pdata->spi_data.mode; - retval = spi_setup(spi); - if (retval < 0) { + error = spi_setup(spi); + if (error < 0) { dev_err(&spi->dev, "spi_setup failed!\n"); - return retval; + return error; } pdata->irq = spi->irq; @@ -413,32 +413,34 @@ static int rmi_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, rmi_spi); - retval = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE); - if (retval) - return retval; + error = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE); + if (error) + return error; /* * Setting the page to zero will (a) make sure the PSR is in a * known state, and (b) make sure we can talk to the device. */ - retval = rmi_set_page(rmi_spi, 0); - if (retval) { + error = rmi_set_page(rmi_spi, 0); + if (error) { dev_err(&spi->dev, "Failed to set page select to 0.\n"); - return retval; + return error; } - retval = rmi_register_transport_device(&rmi_spi->xport); - if (retval) { - dev_err(&spi->dev, "failed to register transport.\n"); - return retval; + dev_info(&spi->dev, "registering SPI-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_spi->xport); + if (error) { + dev_err(&spi->dev, "failed to register sensor: %d\n", error); + return error; } - retval = devm_add_action_or_reset(&spi->dev, + + error = devm_add_action_or_reset(&spi->dev, rmi_spi_unregister_transport, rmi_spi); - if (retval) - return retval; + if (error) + return error; - dev_info(&spi->dev, "registered RMI SPI driver\n"); return 0; } -- cgit From 720bebdff23ed1a9866e737ccdadbf995f6cac7a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 17:28:11 -0800 Subject: Input: eeti_ts - rename eeti_ts_priv to eeti_ts Also rename 'priv' variables to eeti. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 115 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 16023867b9da..74d57ef68663 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -43,7 +43,7 @@ static bool flip_y; module_param(flip_y, bool, 0644); MODULE_PARM_DESC(flip_y, "flip y coordinate"); -struct eeti_ts_priv { +struct eeti_ts { struct i2c_client *client; struct input_dev *input; struct work_struct work; @@ -60,25 +60,25 @@ struct eeti_ts_priv { #define REPORT_BIT_HAS_PRESSURE (1 << 6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) -static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv) +static inline int eeti_ts_irq_active(struct eeti_ts *eeti) { - return gpio_get_value(priv->irq_gpio) == priv->irq_active_high; + return gpio_get_value(eeti->irq_gpio) == eeti->irq_active_high; } static void eeti_ts_read(struct work_struct *work) { char buf[6]; unsigned int x, y, res, pressed, to = 100; - struct eeti_ts_priv *priv = - container_of(work, struct eeti_ts_priv, work); + struct eeti_ts *eeti = + container_of(work, struct eeti_ts, work); - mutex_lock(&priv->mutex); + mutex_lock(&eeti->mutex); - while (eeti_ts_irq_active(priv) && --to) - i2c_master_recv(priv->client, buf, sizeof(buf)); + while (eeti_ts_irq_active(eeti) && --to) + i2c_master_recv(eeti->client, buf, sizeof(buf)); if (!to) { - dev_err(&priv->client->dev, + dev_err(&eeti->client->dev, "unable to clear IRQ - line stuck?\n"); goto out; } @@ -103,62 +103,62 @@ static void eeti_ts_read(struct work_struct *work) y = EETI_MAXVAL - y; if (buf[0] & REPORT_BIT_HAS_PRESSURE) - input_report_abs(priv->input, ABS_PRESSURE, buf[5]); + input_report_abs(eeti->input, ABS_PRESSURE, buf[5]); - input_report_abs(priv->input, ABS_X, x); - input_report_abs(priv->input, ABS_Y, y); - input_report_key(priv->input, BTN_TOUCH, !!pressed); - input_sync(priv->input); + input_report_abs(eeti->input, ABS_X, x); + input_report_abs(eeti->input, ABS_Y, y); + input_report_key(eeti->input, BTN_TOUCH, !!pressed); + input_sync(eeti->input); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&eeti->mutex); } static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { - struct eeti_ts_priv *priv = dev_id; + struct eeti_ts *eeti = dev_id; /* postpone I2C transactions as we are atomic */ - schedule_work(&priv->work); + schedule_work(&eeti->work); return IRQ_HANDLED; } -static void eeti_ts_start(struct eeti_ts_priv *priv) +static void eeti_ts_start(struct eeti_ts *eeti) { - enable_irq(priv->irq); + enable_irq(eeti->irq); /* Read the events once to arm the IRQ */ - eeti_ts_read(&priv->work); + eeti_ts_read(&eeti->work); } -static void eeti_ts_stop(struct eeti_ts_priv *priv) +static void eeti_ts_stop(struct eeti_ts *eeti) { - disable_irq(priv->irq); - cancel_work_sync(&priv->work); + disable_irq(eeti->irq); + cancel_work_sync(&eeti->work); } static int eeti_ts_open(struct input_dev *dev) { - struct eeti_ts_priv *priv = input_get_drvdata(dev); + struct eeti_ts *eeti = input_get_drvdata(dev); - eeti_ts_start(priv); + eeti_ts_start(eeti); return 0; } static void eeti_ts_close(struct input_dev *dev) { - struct eeti_ts_priv *priv = input_get_drvdata(dev); + struct eeti_ts *eeti = input_get_drvdata(dev); - eeti_ts_stop(priv); + eeti_ts_stop(eeti); } static int eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev); - struct eeti_ts_priv *priv; + struct eeti_ts *eeti; struct input_dev *input; unsigned int irq_flags; int err = -ENOMEM; @@ -170,13 +170,14 @@ static int eeti_ts_probe(struct i2c_client *client, * for interrupts to occur. */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { + eeti = kzalloc(sizeof(*eeti), GFP_KERNEL); + if (!eeti) { dev_err(&client->dev, "failed to allocate driver data\n"); return -ENOMEM; } - mutex_init(&priv->mutex); + mutex_init(&eeti->mutex); + input = input_allocate_device(); if (!input) { dev_err(&client->dev, "Failed to allocate input device.\n"); @@ -196,30 +197,30 @@ static int eeti_ts_probe(struct i2c_client *client, input->open = eeti_ts_open; input->close = eeti_ts_close; - priv->client = client; - priv->input = input; - priv->irq_gpio = pdata->irq_gpio; - priv->irq = gpio_to_irq(pdata->irq_gpio); + eeti->client = client; + eeti->input = input; + eeti->irq_gpio = pdata->irq_gpio; + eeti->irq = gpio_to_irq(pdata->irq_gpio); err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name); if (err < 0) goto err1; - priv->irq_active_high = pdata->irq_active_high; + eeti->irq_active_high = pdata->irq_active_high; - irq_flags = priv->irq_active_high ? + irq_flags = eeti->irq_active_high ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; - INIT_WORK(&priv->work, eeti_ts_read); - i2c_set_clientdata(client, priv); - input_set_drvdata(input, priv); + INIT_WORK(&eeti->work, eeti_ts_read); + i2c_set_clientdata(client, eeti); + input_set_drvdata(input, eeti); err = input_register_device(input); if (err) goto err2; - err = request_irq(priv->irq, eeti_ts_isr, irq_flags, - client->name, priv); + err = request_irq(eeti->irq, eeti_ts_isr, irq_flags, + client->name, eeti); if (err) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); goto err3; @@ -229,7 +230,7 @@ static int eeti_ts_probe(struct i2c_client *client, * Disable the device for now. It will be enabled once the * input device is opened. */ - eeti_ts_stop(priv); + eeti_ts_stop(eeti); return 0; @@ -240,23 +241,23 @@ err2: gpio_free(pdata->irq_gpio); err1: input_free_device(input); - kfree(priv); + kfree(eeti); return err; } static int eeti_ts_remove(struct i2c_client *client) { - struct eeti_ts_priv *priv = i2c_get_clientdata(client); + struct eeti_ts *eeti = i2c_get_clientdata(client); - free_irq(priv->irq, priv); + free_irq(eeti->irq, eeti); /* * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it * so that device still works if we reload the driver. */ - enable_irq(priv->irq); + enable_irq(eeti->irq); - input_unregister_device(priv->input); - kfree(priv); + input_unregister_device(eeti->input); + kfree(eeti); return 0; } @@ -264,18 +265,18 @@ static int eeti_ts_remove(struct i2c_client *client) static int __maybe_unused eeti_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct eeti_ts_priv *priv = i2c_get_clientdata(client); - struct input_dev *input_dev = priv->input; + struct eeti_ts *eeti = i2c_get_clientdata(client); + struct input_dev *input_dev = eeti->input; mutex_lock(&input_dev->mutex); if (input_dev->users) - eeti_ts_stop(priv); + eeti_ts_stop(eeti); mutex_unlock(&input_dev->mutex); if (device_may_wakeup(&client->dev)) - enable_irq_wake(priv->irq); + enable_irq_wake(eeti->irq); return 0; } @@ -283,16 +284,16 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev) static int __maybe_unused eeti_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct eeti_ts_priv *priv = i2c_get_clientdata(client); - struct input_dev *input_dev = priv->input; + struct eeti_ts *eeti = i2c_get_clientdata(client); + struct input_dev *input_dev = eeti->input; if (device_may_wakeup(&client->dev)) - disable_irq_wake(priv->irq); + disable_irq_wake(eeti->irq); mutex_lock(&input_dev->mutex); if (input_dev->users) - eeti_ts_start(priv); + eeti_ts_start(eeti); mutex_unlock(&input_dev->mutex); -- cgit From 272c03bb19018a03e50be44b30b4c7485918b8a2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Feb 2017 21:42:43 -0800 Subject: Input: eeti_ts - use BIT(n) Use idiomatic BIT(n) to form single-bit masks. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 74d57ef68663..26b52496748a 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -54,10 +54,10 @@ struct eeti_ts { #define EETI_TS_BITDEPTH (11) #define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1) -#define REPORT_BIT_PRESSED (1 << 0) -#define REPORT_BIT_AD0 (1 << 1) -#define REPORT_BIT_AD1 (1 << 2) -#define REPORT_BIT_HAS_PRESSURE (1 << 6) +#define REPORT_BIT_PRESSED BIT(0) +#define REPORT_BIT_AD0 BIT(1) +#define REPORT_BIT_AD1 BIT(2) +#define REPORT_BIT_HAS_PRESSURE BIT(6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) static inline int eeti_ts_irq_active(struct eeti_ts *eeti) -- cgit From e9f66cdb7d5b9c05a76dde4ca5f217ba4af7f333 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Feb 2017 21:50:13 -0800 Subject: Input: eeti_ts - use get_unaligned_be16() to retrieve data Instead of manually converting big endian data on wire into host endianness, let's use helpers to do that for us. It might save us a few cycles if host endianness matches what's on wire. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 26b52496748a..0e4b19236d68 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -34,6 +34,7 @@ #include #include #include +#include static bool flip_x; module_param(flip_x, bool, 0644); @@ -89,8 +90,9 @@ static void eeti_ts_read(struct work_struct *work) pressed = buf[0] & REPORT_BIT_PRESSED; res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); - x = buf[2] | (buf[1] << 8); - y = buf[4] | (buf[3] << 8); + + x = get_unaligned_be16(&buf[1]); + y = get_unaligned_be16(&buf[3]); /* fix the range to 11 bits */ x >>= res - EETI_TS_BITDEPTH; -- cgit From 42e02a6a0db5499d036ff05710fe7370f9a8683a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Feb 2017 21:53:51 -0800 Subject: Input: eeti_ts - use input_set_capability() Use input_set_capability() instead of manipulating evbit/keybit masks directly. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 0e4b19236d68..b472e0e467e8 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -186,8 +186,7 @@ static int eeti_ts_probe(struct i2c_client *client, goto err1; } - input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOUCH); input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0); input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0); -- cgit From 6f9fab69a21d47ac68e78a8a5c613a2a6156bbb7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Feb 2017 15:54:22 -0800 Subject: Input: eeti_ts - switch to using managed resources Using devm_* APIs simpifies error handling and device teardown. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 70 ++++++++++++------------------------- 1 file changed, 22 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index b472e0e467e8..e99e4fec93f5 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -157,13 +157,14 @@ static void eeti_ts_close(struct input_dev *dev) } static int eeti_ts_probe(struct i2c_client *client, - const struct i2c_device_id *idp) + const struct i2c_device_id *idp) { - struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev); + struct device *dev = &client->dev; + struct eeti_ts_platform_data *pdata = dev_get_platdata(dev); struct eeti_ts *eeti; struct input_dev *input; unsigned int irq_flags; - int err = -ENOMEM; + int error; /* * In contrast to what's described in the datasheet, there seems @@ -172,18 +173,18 @@ static int eeti_ts_probe(struct i2c_client *client, * for interrupts to occur. */ - eeti = kzalloc(sizeof(*eeti), GFP_KERNEL); + eeti = devm_kzalloc(dev, sizeof(*eeti), GFP_KERNEL); if (!eeti) { - dev_err(&client->dev, "failed to allocate driver data\n"); + dev_err(dev, "failed to allocate driver data\n"); return -ENOMEM; } mutex_init(&eeti->mutex); - input = input_allocate_device(); + input = devm_input_allocate_device(dev); if (!input) { - dev_err(&client->dev, "Failed to allocate input device.\n"); - goto err1; + dev_err(dev, "Failed to allocate input device.\n"); + return -ENOMEM; } input_set_capability(input, EV_KEY, BTN_TOUCH); @@ -194,7 +195,6 @@ static int eeti_ts_probe(struct i2c_client *client, input->name = client->name; input->id.bustype = BUS_I2C; - input->dev.parent = &client->dev; input->open = eeti_ts_open; input->close = eeti_ts_close; @@ -203,9 +203,10 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->irq_gpio = pdata->irq_gpio; eeti->irq = gpio_to_irq(pdata->irq_gpio); - err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name); - if (err < 0) - goto err1; + error = devm_gpio_request_one(dev, pdata->irq_gpio, GPIOF_IN, + client->name); + if (error) + return error; eeti->irq_active_high = pdata->irq_active_high; @@ -216,15 +217,16 @@ static int eeti_ts_probe(struct i2c_client *client, i2c_set_clientdata(client, eeti); input_set_drvdata(input, eeti); - err = input_register_device(input); - if (err) - goto err2; + error = input_register_device(input); + if (error) + return error; - err = request_irq(eeti->irq, eeti_ts_isr, irq_flags, - client->name, eeti); - if (err) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - goto err3; + error = devm_request_irq(dev, eeti->irq, eeti_ts_isr, irq_flags, + client->name, eeti); + if (error) { + dev_err(dev, "Unable to request touchscreen IRQ: %d\n", + error); + return error; } /* @@ -233,33 +235,6 @@ static int eeti_ts_probe(struct i2c_client *client, */ eeti_ts_stop(eeti); - return 0; - -err3: - input_unregister_device(input); - input = NULL; /* so we dont try to free it below */ -err2: - gpio_free(pdata->irq_gpio); -err1: - input_free_device(input); - kfree(eeti); - return err; -} - -static int eeti_ts_remove(struct i2c_client *client) -{ - struct eeti_ts *eeti = i2c_get_clientdata(client); - - free_irq(eeti->irq, eeti); - /* - * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it - * so that device still works if we reload the driver. - */ - enable_irq(eeti->irq); - - input_unregister_device(eeti->input); - kfree(eeti); - return 0; } @@ -315,7 +290,6 @@ static struct i2c_driver eeti_ts_driver = { .pm = &eeti_ts_pm, }, .probe = eeti_ts_probe, - .remove = eeti_ts_remove, .id_table = eeti_ts_id, }; -- cgit From 2d3884998945cf3f995e9c2e0f157b59f4ec3e86 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 17:14:33 -0800 Subject: Input: eeti_ts - respect interrupt set in client structure Instead of expecting that GPIO is always interrupt source, let's use interrupt specified in I2C client. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index e99e4fec93f5..ac78ac6d4936 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -49,7 +49,7 @@ struct eeti_ts { struct input_dev *input; struct work_struct work; struct mutex mutex; - int irq_gpio, irq, irq_active_high; + int irq_gpio, irq_active_high; }; #define EETI_TS_BITDEPTH (11) @@ -128,7 +128,7 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id) static void eeti_ts_start(struct eeti_ts *eeti) { - enable_irq(eeti->irq); + enable_irq(eeti->client->irq); /* Read the events once to arm the IRQ */ eeti_ts_read(&eeti->work); @@ -136,7 +136,7 @@ static void eeti_ts_start(struct eeti_ts *eeti) static void eeti_ts_stop(struct eeti_ts *eeti) { - disable_irq(eeti->irq); + disable_irq(eeti->client->irq); cancel_work_sync(&eeti->work); } @@ -201,7 +201,6 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->client = client; eeti->input = input; eeti->irq_gpio = pdata->irq_gpio; - eeti->irq = gpio_to_irq(pdata->irq_gpio); error = devm_gpio_request_one(dev, pdata->irq_gpio, GPIOF_IN, client->name); @@ -221,7 +220,7 @@ static int eeti_ts_probe(struct i2c_client *client, if (error) return error; - error = devm_request_irq(dev, eeti->irq, eeti_ts_isr, irq_flags, + error = devm_request_irq(dev, client->irq, eeti_ts_isr, irq_flags, client->name, eeti); if (error) { dev_err(dev, "Unable to request touchscreen IRQ: %d\n", @@ -252,7 +251,7 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev) mutex_unlock(&input_dev->mutex); if (device_may_wakeup(&client->dev)) - enable_irq_wake(eeti->irq); + enable_irq_wake(client->irq); return 0; } @@ -264,7 +263,7 @@ static int __maybe_unused eeti_ts_resume(struct device *dev) struct input_dev *input_dev = eeti->input; if (device_may_wakeup(&client->dev)) - disable_irq_wake(eeti->irq); + disable_irq_wake(client->irq); mutex_lock(&input_dev->mutex); -- cgit From 173e4d81f76c948acbb49f3900f3ca3f279c5c2a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Feb 2017 23:13:45 -0800 Subject: Input: eeti_ts - use gpio_get_value_cansleep We are reading GPIO state in a non-atomic context (workqueue), so we can use "cansleep" variant, and thus make the driver available on systems where GPIO controllers require sleeping when reading GPIO state. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index ac78ac6d4936..fc61dbea4736 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -63,7 +63,7 @@ struct eeti_ts { static inline int eeti_ts_irq_active(struct eeti_ts *eeti) { - return gpio_get_value(eeti->irq_gpio) == eeti->irq_active_high; + return gpio_get_value_cansleep(eeti->irq_gpio) == eeti->irq_active_high; } static void eeti_ts_read(struct work_struct *work) -- cgit From 0378008a99243fc492e7f0c3aabfeee69a78398c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 17:23:47 -0800 Subject: Input: eeti_ts - switch to using threaded interrupt Instead of having standard interrupt handler and manually firing work item to perform I2C reads, let's switch to threaded interrupts, which were designed specifically for this purpose. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 79 +++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index fc61dbea4736..ee6b87c606ef 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -47,9 +47,8 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate"); struct eeti_ts { struct i2c_client *client; struct input_dev *input; - struct work_struct work; - struct mutex mutex; int irq_gpio, irq_active_high; + bool running; }; #define EETI_TS_BITDEPTH (11) @@ -66,29 +65,11 @@ static inline int eeti_ts_irq_active(struct eeti_ts *eeti) return gpio_get_value_cansleep(eeti->irq_gpio) == eeti->irq_active_high; } -static void eeti_ts_read(struct work_struct *work) +static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) { - char buf[6]; - unsigned int x, y, res, pressed, to = 100; - struct eeti_ts *eeti = - container_of(work, struct eeti_ts, work); - - mutex_lock(&eeti->mutex); - - while (eeti_ts_irq_active(eeti) && --to) - i2c_master_recv(eeti->client, buf, sizeof(buf)); - - if (!to) { - dev_err(&eeti->client->dev, - "unable to clear IRQ - line stuck?\n"); - goto out; - } + unsigned int res; + u16 x, y; - /* drop non-report packets */ - if (!(buf[0] & 0x80)) - goto out; - - pressed = buf[0] & REPORT_BIT_PRESSED; res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); x = get_unaligned_be16(&buf[1]); @@ -109,35 +90,48 @@ static void eeti_ts_read(struct work_struct *work) input_report_abs(eeti->input, ABS_X, x); input_report_abs(eeti->input, ABS_Y, y); - input_report_key(eeti->input, BTN_TOUCH, !!pressed); + input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED); input_sync(eeti->input); - -out: - mutex_unlock(&eeti->mutex); } static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { struct eeti_ts *eeti = dev_id; + int len; + int error; + char buf[6]; - /* postpone I2C transactions as we are atomic */ - schedule_work(&eeti->work); + do { + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + break; + } + + if (buf[0] & 0x80) { + /* Motion packet */ + eeti_ts_report_event(eeti, buf); + } + } while (eeti->running && eeti_ts_irq_active(eeti)); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { + eeti->running = true; + wmb(); enable_irq(eeti->client->irq); - - /* Read the events once to arm the IRQ */ - eeti_ts_read(&eeti->work); } static void eeti_ts_stop(struct eeti_ts *eeti) { + eeti->running = false; + wmb(); disable_irq(eeti->client->irq); - cancel_work_sync(&eeti->work); } static int eeti_ts_open(struct input_dev *dev) @@ -179,8 +173,6 @@ static int eeti_ts_probe(struct i2c_client *client, return -ENOMEM; } - mutex_init(&eeti->mutex); - input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device.\n"); @@ -210,18 +202,15 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->irq_active_high = pdata->irq_active_high; irq_flags = eeti->irq_active_high ? - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; - INIT_WORK(&eeti->work, eeti_ts_read); i2c_set_clientdata(client, eeti); input_set_drvdata(input, eeti); - error = input_register_device(input); - if (error) - return error; - - error = devm_request_irq(dev, client->irq, eeti_ts_isr, irq_flags, - client->name, eeti); + error = devm_request_threaded_irq(dev, client->irq, + NULL, eeti_ts_isr, + irq_flags | IRQF_ONESHOT, + client->name, eeti); if (error) { dev_err(dev, "Unable to request touchscreen IRQ: %d\n", error); @@ -234,6 +223,10 @@ static int eeti_ts_probe(struct i2c_client *client, */ eeti_ts_stop(eeti); + error = input_register_device(input); + if (error) + return error; + return 0; } -- cgit From d422be5f62ef7986d00afa4cd31eda5534ab7991 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 16:22:13 -0800 Subject: Input: eeti_ts - expect platform code to set interrupt trigger Instead of keying interrupt trigger off GPIO polarity, let's rely on platform code to set it up properly for us. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index ee6b87c606ef..3627c7b5f5ec 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -157,7 +157,6 @@ static int eeti_ts_probe(struct i2c_client *client, struct eeti_ts_platform_data *pdata = dev_get_platdata(dev); struct eeti_ts *eeti; struct input_dev *input; - unsigned int irq_flags; int error; /* @@ -201,15 +200,12 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->irq_active_high = pdata->irq_active_high; - irq_flags = eeti->irq_active_high ? - IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW; - i2c_set_clientdata(client, eeti); input_set_drvdata(input, eeti); error = devm_request_threaded_irq(dev, client->irq, NULL, eeti_ts_isr, - irq_flags | IRQF_ONESHOT, + IRQF_ONESHOT, client->name, eeti); if (error) { dev_err(dev, "Unable to request touchscreen IRQ: %d\n", -- cgit From d99caa472c0a28dc95dd9b98c30ee46f9755181f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 19 Feb 2017 17:21:56 -0800 Subject: Input: eeti_ts - switch to gpiod API gpiod API allows standard way of specifying GPIO polarity and takes it into account when reading or setting GPIO state. It also allows us to switch to common way of obtaining GPIO descriptor and away form legacy platform data. Reviewed-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/eeti_ts.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 3627c7b5f5ec..2facad75eb6d 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include #include @@ -47,7 +46,7 @@ MODULE_PARM_DESC(flip_y, "flip y coordinate"); struct eeti_ts { struct i2c_client *client; struct input_dev *input; - int irq_gpio, irq_active_high; + struct gpio_desc *attn_gpio; bool running; }; @@ -60,11 +59,6 @@ struct eeti_ts { #define REPORT_BIT_HAS_PRESSURE BIT(6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) -static inline int eeti_ts_irq_active(struct eeti_ts *eeti) -{ - return gpio_get_value_cansleep(eeti->irq_gpio) == eeti->irq_active_high; -} - static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) { unsigned int res; @@ -115,7 +109,8 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id) /* Motion packet */ eeti_ts_report_event(eeti, buf); } - } while (eeti->running && eeti_ts_irq_active(eeti)); + } while (eeti->running && + eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); return IRQ_HANDLED; } @@ -154,7 +149,6 @@ static int eeti_ts_probe(struct i2c_client *client, const struct i2c_device_id *idp) { struct device *dev = &client->dev; - struct eeti_ts_platform_data *pdata = dev_get_platdata(dev); struct eeti_ts *eeti; struct input_dev *input; int error; @@ -191,14 +185,10 @@ static int eeti_ts_probe(struct i2c_client *client, eeti->client = client; eeti->input = input; - eeti->irq_gpio = pdata->irq_gpio; - - error = devm_gpio_request_one(dev, pdata->irq_gpio, GPIOF_IN, - client->name); - if (error) - return error; - eeti->irq_active_high = pdata->irq_active_high; + eeti->attn_gpio = devm_gpiod_get_optional(dev, "attn", GPIOD_IN); + if (IS_ERR(eeti->attn_gpio)) + return PTR_ERR(eeti->attn_gpio); i2c_set_clientdata(client, eeti); input_set_drvdata(input, eeti); -- cgit From dd04dc6dbd7f32b904c3b9916f5eb6be6fc2bb58 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Tue, 4 Apr 2017 10:06:57 -0700 Subject: Input: sur40 - fix bad endianness handling in sur40_poll sparse says: sur40.c:372:40: warning: restricted __le32 degrades to integer the header's data is __le32 so we need to convert it before comparing. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sur40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 4c0eecae065c..128e5bd74720 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -369,7 +369,7 @@ static void sur40_poll(struct input_polled_dev *polldev) * packet ID will usually increase in the middle of a series * instead of at the end. */ - if (packet_id != header->packet_id) + if (packet_id != le32_to_cpu(header->packet_id)) dev_dbg(sur40->dev, "packet ID mismatch\n"); packet_blobs = result / sizeof(struct sur40_blob); -- cgit From f6bcc91ba632ce35005ed8a3cfa01a2498d2d96a Mon Sep 17 00:00:00 2001 From: Damien Riegel Date: Tue, 4 Apr 2017 16:25:42 -0700 Subject: Input: pm8xxx-vib - reorder header alphabetically Signed-off-by: Damien Riegel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 5113877153d7..580448170342 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -10,13 +10,13 @@ * GNU General Public License for more details. */ -#include -#include #include -#include #include -#include +#include +#include +#include #include +#include #define VIB_DRV 0x4A -- cgit From 2de3b7048d029fef8f5c25faa1483f5e66402e49 Mon Sep 17 00:00:00 2001 From: Damien Riegel Date: Tue, 4 Apr 2017 16:25:57 -0700 Subject: Input: pm8xxx-vib - parametrize the driver In order to prepare this driver to support other vibrators of the same kind, move some hardcoded values to a structure holding register parameters (address, mask, shit of the control register). Signed-off-by: Damien Riegel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 49 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 580448170342..cf94fa3f5f2e 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -14,36 +14,47 @@ #include #include #include +#include #include #include #include -#define VIB_DRV 0x4A - -#define VIB_DRV_SEL_MASK 0xf8 -#define VIB_DRV_SEL_SHIFT 0x03 -#define VIB_DRV_EN_MANUAL_MASK 0xfc - #define VIB_MAX_LEVEL_mV (3100) #define VIB_MIN_LEVEL_mV (1200) #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) #define MAX_FF_SPEED 0xff +struct pm8xxx_regs { + unsigned int drv_addr; + unsigned int drv_mask; + unsigned int drv_shift; + unsigned int drv_en_manual_mask; +}; + +static const struct pm8xxx_regs pm8058_regs = { + .drv_addr = 0x4A, + .drv_mask = 0xf8, + .drv_shift = 3, + .drv_en_manual_mask = 0xfc, +}; + /** * struct pm8xxx_vib - structure to hold vibrator data * @vib_input_dev: input device supporting force feedback * @work: work structure to set the vibration parameters * @regmap: regmap for register read/write + * @regs: registers' info * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip - * @reg_vib_drv: VIB_DRV register value + * @reg_vib_drv: regs->drv_addr register value */ struct pm8xxx_vib { struct input_dev *vib_input_dev; struct work_struct work; struct regmap *regmap; + const struct pm8xxx_regs *regs; int speed; int level; bool active; @@ -59,13 +70,14 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) { int rc; unsigned int val = vib->reg_vib_drv; + const struct pm8xxx_regs *regs = vib->regs; if (on) - val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); + val |= (vib->level << regs->drv_shift) & regs->drv_mask; else - val &= ~VIB_DRV_SEL_MASK; + val &= ~regs->drv_mask; - rc = regmap_write(vib->regmap, VIB_DRV, val); + rc = regmap_write(vib->regmap, regs->drv_addr, val); if (rc < 0) return rc; @@ -80,10 +92,11 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) static void pm8xxx_work_handler(struct work_struct *work) { struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); + const struct pm8xxx_regs *regs = vib->regs; int rc; unsigned int val; - rc = regmap_read(vib->regmap, VIB_DRV, &val); + rc = regmap_read(vib->regmap, regs->drv_addr, &val); if (rc < 0) return; @@ -147,6 +160,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) struct input_dev *input_dev; int error; unsigned int val; + const struct pm8xxx_regs *regs; vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); if (!vib) @@ -163,16 +177,19 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) INIT_WORK(&vib->work, pm8xxx_work_handler); vib->vib_input_dev = input_dev; + regs = of_device_get_match_data(&pdev->dev); + /* operate in manual mode */ - error = regmap_read(vib->regmap, VIB_DRV, &val); + error = regmap_read(vib->regmap, regs->drv_addr, &val); if (error < 0) return error; - val &= ~VIB_DRV_EN_MANUAL_MASK; - error = regmap_write(vib->regmap, VIB_DRV, val); + val &= regs->drv_en_manual_mask; + error = regmap_write(vib->regmap, regs->drv_addr, val); if (error < 0) return error; + vib->regs = regs; vib->reg_vib_drv = val; input_dev->name = "pm8xxx_vib_ffmemless"; @@ -212,8 +229,8 @@ static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); static const struct of_device_id pm8xxx_vib_id_table[] = { - { .compatible = "qcom,pm8058-vib" }, - { .compatible = "qcom,pm8921-vib" }, + { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); -- cgit From d4c7c5c96c9254017a1aff596a1f43b5bcef7bef Mon Sep 17 00:00:00 2001 From: Damien Riegel Date: Tue, 4 Apr 2017 16:27:36 -0700 Subject: Input: pm8xxx-vib - handle separate enable register Some PMIC vibrator IPs use a separate enable register to turn the vibrator on and off. To detect if a vibrator uses this feature, rely on the enable_mask being non-zero. Signed-off-by: Damien Riegel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pm8xxx-vibrator.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index cf94fa3f5f2e..3dc8ffbc6b9d 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,9 @@ #define MAX_FF_SPEED 0xff struct pm8xxx_regs { + unsigned int enable_addr; + unsigned int enable_mask; + unsigned int drv_addr; unsigned int drv_mask; unsigned int drv_shift; @@ -82,7 +86,12 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) return rc; vib->reg_vib_drv = val; - return 0; + + if (regs->enable_mask) + rc = regmap_update_bits(vib->regmap, regs->enable_addr, + on ? regs->enable_mask : 0, val); + + return rc; } /** -- cgit From 792ad66839b89802673ec1398161234674638255 Mon Sep 17 00:00:00 2001 From: Damien Riegel Date: Tue, 4 Apr 2017 16:29:59 -0700 Subject: Input: pm8xxx-vib - add support for pm8916's vibrator Add pm8xxx_regs for this PMIC and the device tree match table entry. Signed-off-by: Damien Riegel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 2 +- drivers/input/misc/pm8xxx-vibrator.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5b6c52210d20..79d0be9885c5 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -143,7 +143,7 @@ config INPUT_PM8941_PWRKEY config INPUT_PM8XXX_VIBRATOR tristate "Qualcomm PM8XXX vibrator support" - depends on MFD_PM8XXX + depends on MFD_PM8XXX || MFD_SPMI_PMIC select INPUT_FF_MEMLESS help This option enables device driver support for the vibrator diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 3dc8ffbc6b9d..7dd1c1fbe42a 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -43,6 +43,15 @@ static const struct pm8xxx_regs pm8058_regs = { .drv_en_manual_mask = 0xfc, }; +static struct pm8xxx_regs pm8916_regs = { + .enable_addr = 0xc046, + .enable_mask = BIT(7), + .drv_addr = 0xc041, + .drv_mask = 0x1F, + .drv_shift = 0, + .drv_en_manual_mask = 0, +}; + /** * struct pm8xxx_vib - structure to hold vibrator data * @vib_input_dev: input device supporting force feedback @@ -240,6 +249,7 @@ static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); static const struct of_device_id pm8xxx_vib_id_table[] = { { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); -- cgit From dd224085d73ab04d14fe78a5fd9970fa808a60fb Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 10 Apr 2017 20:34:19 -0700 Subject: Input: soc_button_array - properly map usage 0x07/0xe3 to KEY_LEFTMETA When submitting the support for the ACPI0011 windows tablet keys device I mapped the "windows" logo homekey to KEY_HOMEPAGE. But this is inconsistent with how it is done on windows tablets using the old PNP0C40 ACPI device and it does not match the HUT spec, which says that usage-page 7 usage 0xe3 is "Keyboard Left GUI". This commit maps usage-page 7 usage 0xe3 to KEY_LEFTMETA fixing this. Fixes: 4c3362f44980 ("Input: soc_button_array - add support for ACPI 6.0...") Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index 95b787a63560..f210a3322559 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -187,7 +187,7 @@ static int soc_button_parse_btn_desc(struct device *dev, info->wakeup = true; } else if (upage == 0x07 && usage == 0xe3) { info->name = "home"; - info->event_code = KEY_HOMEPAGE; + info->event_code = KEY_LEFTMETA; info->wakeup = true; } else if (upage == 0x0c && usage == 0xe9) { info->name = "volume_up"; -- cgit From c9a9b72f34bf67a49743b26ab1f94c1349a389ad Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 10 Apr 2017 20:37:40 -0700 Subject: Input: db9 - use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/db9.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index da326090c2b0..f4ad83eab67f 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -609,9 +609,7 @@ static void db9_attach(struct parport *pp) db9->pd = pd; db9->mode = mode; db9->parportno = pp->number; - init_timer(&db9->timer); - db9->timer.data = (long) db9; - db9->timer.function = db9_timer; + setup_timer(&db9->timer, db9_timer, (long)db9); for (i = 0; i < (min(db9_mode->n_pads, DB9_MAX_DEVICES)); i++) { -- cgit From d8f2bed04c9925dc6fc8c1b60c145a044869a82f Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 10 Apr 2017 20:37:53 -0700 Subject: Input: gameport - use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/gameport.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 092cc4188b57..cedc665364cd 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -542,9 +542,8 @@ static void gameport_init_port(struct gameport *gameport) INIT_LIST_HEAD(&gameport->node); spin_lock_init(&gameport->timer_lock); - init_timer(&gameport->poll_timer); - gameport->poll_timer.function = gameport_run_poll_handler; - gameport->poll_timer.data = (unsigned long)gameport; + setup_timer(&gameport->poll_timer, gameport_run_poll_handler, + (unsigned long)gameport); } /* -- cgit From cfecc1ebdc9315ef6164b396629ff2936dbba0aa Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 10 Apr 2017 20:38:10 -0700 Subject: Input: locomokbd - use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/locomokbd.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index c94d610b9d78..0d74312d5b02 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -264,9 +264,8 @@ static int locomokbd_probe(struct locomo_dev *dev) spin_lock_init(&locomokbd->lock); - init_timer(&locomokbd->timer); - locomokbd->timer.function = locomokbd_timer_callback; - locomokbd->timer.data = (unsigned long) locomokbd; + setup_timer(&locomokbd->timer, locomokbd_timer_callback, + (unsigned long)locomokbd); locomokbd->suspend_jiffies = jiffies; -- cgit From bee84493318843ffba9705924469369b9b244ddf Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Mon, 10 Apr 2017 20:38:30 -0700 Subject: Input: turbografx - use setup_timer Use setup_timer() instead of init_timer() to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/turbografx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 77f575dd0901..a1fdc75a438d 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -200,9 +200,7 @@ static void tgfx_attach(struct parport *pp) mutex_init(&tgfx->sem); tgfx->pd = pd; tgfx->parportno = pp->number; - init_timer(&tgfx->timer); - tgfx->timer.data = (long) tgfx; - tgfx->timer.function = tgfx_timer; + setup_timer(&tgfx->timer, tgfx_timer, (long)tgfx); for (i = 0; i < n_devs; i++) { if (n_buttons[i] < 1) -- cgit From c5cb37d0d62c58320f0a86777b738fb28272245b Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 10 Apr 2017 20:39:22 -0700 Subject: Input: yealink - define packet offset __be16 instead of u16 sparse says warning: incorrect type in assignment (different base types) expected unsigned short [unsigned] [usertype] offset got restricted __be16 [usertype] for every usage of cpu_to_be16 in yealink.c. Defining it __be16 in the first place shouldn't hurt. Signed-off-by: Martin Kepplinger Signed-off-by: Henk.Vergonet@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/yealink.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h index 1e0f52397010..934c247f8a0f 100644 --- a/drivers/input/misc/yealink.h +++ b/drivers/input/misc/yealink.h @@ -28,7 +28,7 @@ struct yld_ctl_packet { u8 cmd; /* command code, see below */ u8 size; /* 1-11, size of used data bytes. */ - u16 offset; /* internal packet offset */ + __be16 offset; /* internal packet offset */ u8 data[11]; s8 sum; /* negative sum of 15 preceding bytes */ } __attribute__ ((packed)); -- cgit From 81093c9848a781b85163d06de92ef8f84528cf6a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 10 Apr 2017 20:43:04 -0700 Subject: Input: xpad - support some quirky Xbox One pads There are several quirky Xbox One pads that depend on initialization packets that the Microsoft pads don't require. To deal with these, I've added a mechanism for issuing device-specific initialization packets using a VID/PID-based quirks list. For the initial set of init quirks, I have added quirk handling from Valve's Steam Link xpad driver[0] and the 360Controller project[1] for macOS to enable some new pads to work properly. This should enable full functionality on the following quirky pads: 0x0e6f:0x0165 - Titanfall 2 gamepad (previously fully non-functional) 0x0f0d:0x0067 - Hori Horipad (analog sticks previously non-functional) 0x24c6:0x541a - PowerA Xbox One pad (previously fully non-functional) 0x24c6:0x542a - PowerA Xbox One pad (previously fully non-functional) 0x24c6:0x543a - PowerA Xbox One pad (previously fully non-functional) [0]: https://github.com/ValveSoftware/steamlink-sdk/blob/master/kernel/drivers/input/joystick/xpad.c [1]: https://github.com/360Controller/360Controller Signed-off-by: Cameron Gutman Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 114 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 155fcb3b6230..8a41926dab0a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -337,6 +337,64 @@ static struct usb_device_id xpad_table[] = { MODULE_DEVICE_TABLE(usb, xpad_table); +struct xboxone_init_packet { + u16 idVendor; + u16 idProduct; + const u8 *data; + u8 len; +}; + +#define XBOXONE_INIT_PKT(_vid, _pid, _data) \ + { \ + .idVendor = (_vid), \ + .idProduct = (_pid), \ + .data = (_data), \ + .len = ARRAY_SIZE(_data), \ + } + + +/* + * This packet is required for all Xbox One pads with 2015 + * or later firmware installed (or present from the factory). + */ +static const u8 xboxone_fw2015_init[] = { + 0x05, 0x20, 0x00, 0x01, 0x00 +}; + +/* + * This packet is required for the Titanfall 2 Xbox One pads + * (0x0e6f:0x0165) to finish initialization and for Hori pads + * (0x0f0d:0x0067) to make the analog sticks work. + */ +static const u8 xboxone_hori_init[] = { + 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a, + 0x00, 0x00, 0x00, 0x80, 0x00 +}; + +/* + * A rumble packet is required for some PowerA pads to start + * sending input reports. One of those pads is (0x24c6:0x543a). + */ +static const u8 xboxone_zerorumble_init[] = { + 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* + * This specifies the selection of init packets that a gamepad + * will be sent on init *and* the order in which they will be + * sent. The correct sequence number will be added when the + * packet is going to be sent. + */ +static const struct xboxone_init_packet xboxone_init_packets[] = { + XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), + XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_zerorumble_init), + XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_zerorumble_init), + XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_zerorumble_init), +}; + struct xpad_output_packet { u8 data[XPAD_PKT_LEN]; u8 len; @@ -373,6 +431,7 @@ struct usb_xpad { struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; int last_out_packet; + int init_seq; #if defined(CONFIG_JOYSTICK_XPAD_LEDS) struct xpad_led *led; @@ -747,12 +806,48 @@ exit: __func__, retval); } +/* Callers must hold xpad->odata_lock spinlock */ +static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) +{ + const struct xboxone_init_packet *init_packet; + + if (xpad->xtype != XTYPE_XBOXONE) + return false; + + /* Perform initialization sequence for Xbox One pads that require it */ + while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) { + init_packet = &xboxone_init_packets[xpad->init_seq++]; + + if (init_packet->idVendor != 0 && + init_packet->idVendor != xpad->dev->id.vendor) + continue; + + if (init_packet->idProduct != 0 && + init_packet->idProduct != xpad->dev->id.product) + continue; + + /* This packet applies to our device, so prepare to send it */ + memcpy(xpad->odata, init_packet->data, init_packet->len); + xpad->irq_out->transfer_buffer_length = init_packet->len; + + /* Update packet with current sequence number */ + xpad->odata[2] = xpad->odata_serial++; + return true; + } + + return false; +} + /* Callers must hold xpad->odata_lock spinlock */ static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) { struct xpad_output_packet *pkt, *packet = NULL; int i; + /* We may have init packets to send before we can send user commands */ + if (xpad_prepare_next_init_packet(xpad)) + return true; + for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) xpad->last_out_packet = 0; @@ -938,24 +1033,17 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) static int xpad_start_xbox_one(struct usb_xpad *xpad) { - struct xpad_output_packet *packet = - &xpad->out_packets[XPAD_OUT_CMD_IDX]; unsigned long flags; int retval; spin_lock_irqsave(&xpad->odata_lock, flags); - /* Xbox one controller needs to be initialized. */ - packet->data[0] = 0x05; - packet->data[1] = 0x20; - packet->data[2] = xpad->odata_serial++; /* packet serial */ - packet->data[3] = 0x01; /* rumble bit enable? */ - packet->data[4] = 0x00; - packet->len = 5; - packet->pending = true; - - /* Reset the sequence so we send out start packet first */ - xpad->last_out_packet = -1; + /* + * Begin the init sequence by attempting to send a packet. + * We will cycle through the init packet sequence before + * sending any packets from the output ring. + */ + xpad->init_seq = 0; retval = xpad_try_sending_next_out_packet(xpad); spin_unlock_irqrestore(&xpad->odata_lock, flags); -- cgit From 9bb9dc1359ef40a10153cd8c7106dd9d9e8aa1a3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 10 Apr 2017 20:48:16 -0700 Subject: Input: omap-keypad - fix error handling code According to the previous error handling code, it is likely that 'goto err_free_keymap' is expected here in order to avoid a memory leak in error handling path. Signed-off-by: Christophe JAILLET Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/omap4-keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index ebc67ba41fe2..940d38b08e6b 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -358,7 +358,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) "omap4-keypad", keypad_data); if (error) { dev_err(&pdev->dev, "failed to register interrupt\n"); - goto err_free_input; + goto err_free_keymap; } device_init_wakeup(&pdev->dev, true); -- cgit From c286841720b2e33795bea6cc4c71d50cd6cd8123 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 12 Apr 2017 08:33:50 -0700 Subject: Input: imx6ul_tsc - fix error handling If imx6ul_tsc_init() fails we should not return directly. We should disable the previously acquired clocks in this case. Signed-off-by: Fabio Estevam Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 7098e0a47019..ee82a975bfd2 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -337,11 +337,20 @@ static int imx6ul_tsc_open(struct input_dev *input_dev) dev_err(tsc->dev, "Could not prepare or enable the tsc clock: %d\n", err); - clk_disable_unprepare(tsc->adc_clk); - return err; + goto disable_adc_clk; } - return imx6ul_tsc_init(tsc); + err = imx6ul_tsc_init(tsc); + if (err) + goto disable_tsc_clk; + + return 0; + +disable_tsc_clk: + clk_disable_unprepare(tsc->tsc_clk); +disable_adc_clk: + clk_disable_unprepare(tsc->adc_clk); + return err; } static void imx6ul_tsc_close(struct input_dev *input_dev) -- cgit From 71f9f08103cb02f3d5bfad91cb570dcd2d8ed0cb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 12 Apr 2017 08:34:03 -0700 Subject: Input: lpc32xx_ts - check for clk_prepare_enable() error clk_prepare_enable() may fail, so we better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/lpc32xx_ts.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index e0baa7de4102..4eb31ec10b18 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -142,11 +142,14 @@ static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc) clk_disable_unprepare(tsc->clk); } -static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) +static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) { u32 tmp; + int err; - clk_prepare_enable(tsc->clk); + err = clk_prepare_enable(tsc->clk); + if (err) + return err; tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP; @@ -184,15 +187,15 @@ static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) /* Enable automatic ts event capture */ tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN); + + return 0; } static int lpc32xx_ts_open(struct input_dev *dev) { struct lpc32xx_tsc *tsc = input_get_drvdata(dev); - lpc32xx_setup_tsc(tsc); - - return 0; + return lpc32xx_setup_tsc(tsc); } static void lpc32xx_ts_close(struct input_dev *dev) -- cgit From 2274c98720fece37fb4947e94ec03b15e62164a9 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Wed, 12 Apr 2017 08:41:19 -0700 Subject: Input: ar1021_i2c - coding style fixes Use the common kernel coding style and corrently align parameters with open parenthesis. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ar1021_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 6562b17117f7..2e7500edd477 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -33,7 +33,7 @@ static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id) int retval; retval = i2c_master_recv(ar1021->client, - ar1021->data, sizeof(ar1021->data)); + ar1021->data, sizeof(ar1021->data)); if (retval != sizeof(ar1021->data)) goto out; @@ -73,7 +73,7 @@ static void ar1021_i2c_close(struct input_dev *dev) } static int ar1021_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct ar1021_i2c *ar1021; struct input_dev *input; -- cgit From 95123fc43560d6f4a60e74f72836e63cd8848f76 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 12 Dec 2016 15:32:57 -0800 Subject: Input: ar1021_i2c - fix too long name in driver's device table The name field in structure i2c_device_id is 20 characters, and we expect it to be NULL-terminated, however we are trying to stuff it with 21 bytes and thus NULL-terminator is lost. This causes issues when one creates device with name "MICROCHIP_AR1021_I2C" as i2c core cuts off the last "C", and automatic module loading by alias does not work as result. The -I2C suffix in the device name is superfluous, we know what bus we are dealing with, so let's drop it. Also, no other driver uses capitals, and the manufacturer name is normally not included, except in very rare cases of incompatible name collisions. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=116211 Fixes: dd4cae8bf166 ("Input: Add Microchip AR1021 i2c touchscreen") Reviewed-By: Christian Gmeiner Tested-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ar1021_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 2e7500edd477..6797e123925a 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -151,7 +151,7 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "MICROCHIP_AR1021_I2C", 0 }, + { "ar1021", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); -- cgit From 61e977b7a43111909a4513529187f56726abda9e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 13 Apr 2017 16:36:42 -0700 Subject: Input: ar1021_i2c - do not force raising edge IRQ trigger We should not be forcing edge triggered interrupt, but rather let platform decide the kind of trigger it needs to use. Also, the driver is not quite safe with regard to edge-triggered interrupts as it does not try to kick the controller after requesting/enabling IRQ. Reviewed-By: Christian Gmeiner Tested-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ar1021_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 6797e123925a..6c3c79b7ff51 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -109,7 +109,7 @@ static int ar1021_i2c_probe(struct i2c_client *client, error = devm_request_threaded_irq(&client->dev, client->irq, NULL, ar1021_i2c_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, + IRQF_ONESHOT, "ar1021_i2c", ar1021); if (error) { dev_err(&client->dev, -- cgit From 021cbc1edadf466d088da1345264e1840c6665d3 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Fri, 14 Apr 2017 10:14:06 -0700 Subject: Input: ar1021_i2c - highlight support for AR1020 ar1021_i2c also supports the ar1020 device I'm using. This is tested. They also share the same datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/40001393C.pdf So let users see that they have a compatible in front of them by adding AR1020 to the driver's description. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 6 +++--- drivers/input/touchscreen/ar1021_i2c.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6515e649e204..e3c5112505e4 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -93,11 +93,11 @@ config TOUCHSCREEN_AD7879_SPI module will be called ad7879-spi. config TOUCHSCREEN_AR1021_I2C - tristate "Microchip AR1021 i2c touchscreen" + tristate "Microchip AR1020/1021 i2c touchscreen" depends on I2C && OF help - Say Y here if you have the Microchip AR1021 touchscreen controller - chip in your system. + Say Y here if you have the Microchip AR1020 or AR1021 touchscreen + controller chip in your system. If unsure, say N. diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 6c3c79b7ff51..1a94d8bfec54 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -1,5 +1,5 @@ /* - * Microchip AR1021 driver for I2C + * Microchip AR1020 and AR1021 driver for I2C * * Author: Christian Gmeiner * @@ -175,5 +175,5 @@ static struct i2c_driver ar1021_i2c_driver = { module_i2c_driver(ar1021_i2c_driver); MODULE_AUTHOR("Christian Gmeiner "); -MODULE_DESCRIPTION("Microchip AR1021 I2C Driver"); +MODULE_DESCRIPTION("Microchip AR1020 and AR1021 I2C Driver"); MODULE_LICENSE("GPL"); -- cgit From 72fe38704c92e63459dd362cd27f9b32a63bbb48 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Fri, 14 Apr 2017 14:42:44 -0700 Subject: Input: synaptics-rmi4 - use dev_driver_string when registering interrupt When IRQ handling was moved to rmi_driver in 3aeed5b the naming of the interrupt changed from "rmi4_i2c" to "2-0020" (or similar). This patch restores the previous behaviour and makes the interrupt easier to identify in /proc/interrupts. Signed-off-by: Nick Dyer Tested-by: Chris Healy Acked-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 821dc47b6eef..4f2bb5947a4e 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -251,7 +251,7 @@ static int rmi_irq_init(struct rmi_device *rmi_dev) ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL, rmi_irq_fn, irq_flags | IRQF_ONESHOT, - dev_name(rmi_dev->xport->dev), + dev_driver_string(rmi_dev->xport->dev), rmi_dev); if (ret < 0) { dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n", -- cgit From 25670fb0373013ad9cdb2676afb468e4d88e1d53 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Fri, 14 Apr 2017 14:43:25 -0700 Subject: Input: synaptics-rmi4 - change F12 clip to inactive border debug The data in F12_2D_Ctrl8 corresponds to the inactive border width used by the RMI device. It is not in pixel units and should not be treated as a clip value. Signed-off-by: Nick Dyer Tested-by: Chris Healy Acked-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f12.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 07aff4356fe0..8b0db086d68a 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -113,20 +113,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) } if (rmi_register_desc_has_subpacket(item, 2)) { - sensor->axis_align.clip_x_low = buf[offset]; - sensor->axis_align.clip_x_high = sensor->max_x - - buf[offset + 1]; - sensor->axis_align.clip_y_low = buf[offset + 2]; - sensor->axis_align.clip_y_high = sensor->max_y - - buf[offset + 3]; + /* Units 1/128 sensor pitch */ + rmi_dbg(RMI_DEBUG_FN, &fn->dev, + "%s: Inactive Border xlo:%d xhi:%d ylo:%d yhi:%d\n", + __func__, + buf[offset], buf[offset + 1], + buf[offset + 2], buf[offset + 3]); + offset += 4; } - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n", - __func__, - sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high, - sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high); - if (rmi_register_desc_has_subpacket(item, 3)) { rx_receivers = buf[offset]; tx_receivers = buf[offset + 1]; -- cgit From a6869e3a76f46b26a2b208882701fa17537b18cd Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Fri, 14 Apr 2017 14:44:08 -0700 Subject: Input: synaptics-rmi4 - enable IRQ operation in F34 V7 The polled firmware update proved unreliable when testing on S7817. Use attention to signal commands are complete. Signed-off-by: Nick Dyer Tested-by: Chris Healy Acked-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f34.c | 27 +++++++--- drivers/input/rmi4/rmi_f34.h | 7 +-- drivers/input/rmi4/rmi_f34v7.c | 117 ++++++++++++++++++++++------------------- 3 files changed, 83 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 425fe140e9df..b8ee78e0d61f 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -105,16 +105,27 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits) { struct f34_data *f34 = dev_get_drvdata(&fn->dev); int ret; + u8 status; - if (f34->bl_version != 5) - return 0; + if (f34->bl_version == 5) { + ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, + &status); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", + __func__, status, ret); - ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", - __func__, f34->v5.status, ret); - - if (!ret && !(f34->v5.status & 0x7f)) - complete(&f34->v5.cmd_done); + if (!ret && !(status & 0x7f)) + complete(&f34->v5.cmd_done); + } else { + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.data_base_addr + + f34->v7.off.flash_status, + &status, sizeof(status)); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", + __func__, status, ret); + + if (!ret && !(status & 0x1f)) + complete(&f34->v7.cmd_done); + } return 0; } diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h index 43a91349b28d..32c4e9581c68 100644 --- a/drivers/input/rmi4/rmi_f34.h +++ b/drivers/input/rmi4/rmi_f34.h @@ -30,6 +30,7 @@ #define F34_IDLE_WAIT_MS 500 #define F34_ENABLE_WAIT_MS 300 #define F34_ERASE_WAIT_MS 5000 +#define F34_WRITE_WAIT_MS 3000 #define F34_BOOTLOADER_ID_LEN 2 @@ -47,11 +48,6 @@ #define CONFIG_ID_SIZE 32 #define PRODUCT_ID_SIZE 10 -#define ENABLE_WAIT_MS (1 * 1000) -#define WRITE_WAIT_MS (3 * 1000) - -#define MIN_SLEEP_TIME_US 50 -#define MAX_SLEEP_TIME_US 100 #define HAS_BSR BIT(5) #define HAS_CONFIG_ID BIT(3) @@ -292,6 +288,7 @@ struct f34v7_data { const void *config_data; const void *image; + struct completion cmd_done; }; struct f34_data { diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index 56c6c39ad31e..10c0d11b72c9 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "rmi_driver.h" #include "rmi_f34.h" @@ -31,7 +32,7 @@ static int rmi_f34v7_read_flash_status(struct f34_data *f34) sizeof(status)); if (ret < 0) { rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, - "%s: Failed to read flash status\n", __func__); + "%s: Error %d reading flash status\n", __func__, ret); return ret; } @@ -60,28 +61,17 @@ static int rmi_f34v7_read_flash_status(struct f34_data *f34) static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms) { - int count = 0; - int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + unsigned long timeout; - do { - usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); - - count++; - - rmi_f34v7_read_flash_status(f34); - - if ((f34->v7.command == v7_CMD_IDLE) - && (f34->v7.flash_status == 0x00)) { - rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, - "Idle status detected\n"); - return 0; - } - } while (count < timeout_count); + timeout = msecs_to_jiffies(timeout_ms); - dev_err(&f34->fn->dev, - "%s: Timed out waiting for idle status\n", __func__); + if (!wait_for_completion_timeout(&f34->v7.cmd_done, timeout)) { + dev_warn(&f34->fn->dev, "%s: Timed out waiting for idle status\n", + __func__); + return -ETIMEDOUT; + } - return -ETIMEDOUT; + return 0; } static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34, @@ -285,9 +275,10 @@ static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd) return 0; } -static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) +static int rmi_f34v7_read_partition_table(struct f34_data *f34) { int ret; + unsigned long timeout; u8 base; __le16 length; u16 block_number = 0; @@ -320,6 +311,8 @@ static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) return ret; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG); if (ret < 0) { dev_err(&f34->fn->dev, "%s: Failed to write command\n", @@ -327,11 +320,15 @@ static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) return ret; } - ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n", - __func__); - return ret; + timeout = msecs_to_jiffies(F34_WRITE_WAIT_MS); + while (time_before(jiffies, timeout)) { + usleep_range(5000, 6000); + rmi_f34v7_read_flash_status(f34); + + if (f34->v7.command == v7_CMD_IDLE && + f34->v7.flash_status == 0x00) { + break; + } } ret = rmi_read_block(f34->fn->rmi_dev, @@ -570,7 +567,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) f34->v7.read_config_buf_size = f34->v7.partition_table_bytes; ptable = f34->v7.read_config_buf; - ret = rmi_f34v7_read_f34v7_partition_table(f34); + ret = rmi_f34v7_read_partition_table(f34); if (ret < 0) { dev_err(&f34->fn->dev, "%s: Failed to read partition table\n", __func__); @@ -666,6 +663,8 @@ static int rmi_f34v7_erase_config(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing config...\n"); + init_completion(&f34->v7.cmd_done); + switch (f34->v7.config_area) { case v7_UI_CONFIG_AREA: ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG); @@ -684,11 +683,11 @@ static int rmi_f34v7_erase_config(struct f34_data *f34) break; } - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; - return ret; + return 0; } static int rmi_f34v7_erase_guest_code(struct f34_data *f34) @@ -697,11 +696,13 @@ static int rmi_f34v7_erase_guest_code(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing guest code...\n"); + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; @@ -714,11 +715,13 @@ static int rmi_f34v7_erase_all(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing firmware...\n"); + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; @@ -743,8 +746,8 @@ static int rmi_f34v7_erase_all(struct f34_data *f34) return 0; } -static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, - u8 command) +static int rmi_f34v7_read_blocks(struct f34_data *f34, + u16 block_cnt, u8 command) { int ret; u8 base; @@ -787,17 +790,15 @@ static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, return ret; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, command); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, - "%s: Wait for idle failed (%d blks remaining)\n", - __func__, remaining); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); + if (ret < 0) return ret; - } ret = rmi_read_block(f34->fn->rmi_dev, base + f34->v7.off.payload, @@ -853,6 +854,8 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, transfer = min(remaining, max_transfer); put_unaligned_le16(transfer, &length); + init_completion(&f34->v7.cmd_done); + ret = rmi_write_block(f34->fn->rmi_dev, base + f34->v7.off.transfer_length, &length, sizeof(length)); @@ -877,13 +880,9 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, return ret; } - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, - "%s: Failed wait for idle (%d blks remaining)\n", - __func__, remaining); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); + if (ret < 0) return ret; - } block_ptr += (transfer * f34->v7.block_size); remaining -= transfer; @@ -945,6 +944,8 @@ static int rmi_f34v7_write_flash_config(struct f34_data *f34) return -EINVAL; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG); if (ret < 0) return ret; @@ -952,7 +953,7 @@ static int rmi_f34v7_write_flash_config(struct f34_data *f34) rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Erase flash config command written\n", __func__); - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_WRITE_WAIT_MS); if (ret < 0) return ret; @@ -981,7 +982,7 @@ static int rmi_f34v7_write_partition_table(struct f34_data *f34) f34->v7.read_config_buf_size = f34->v7.config_size; - ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG); + ret = rmi_f34v7_read_blocks(f34, block_count, v7_CMD_READ_CONFIG); if (ret < 0) return ret; @@ -1287,6 +1288,8 @@ static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) { int ret; + f34->fn->rmi_dev->driver->set_irq_bits(f34->fn->rmi_dev, f34->fn->irq_mask); + ret = rmi_f34v7_read_flash_status(f34); if (ret < 0) return ret; @@ -1294,19 +1297,16 @@ static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) if (f34->v7.in_bl_mode) return 0; + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); if (ret < 0) return ret; - if (!f34->v7.in_bl_mode) { - dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__); - return -EINVAL; - } - return 0; } @@ -1314,6 +1314,8 @@ int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw) { int ret = 0; + f34->fn->rmi_dev->driver->set_irq_bits(f34->fn->rmi_dev, f34->fn->irq_mask); + f34->v7.config_area = v7_UI_CONFIG_AREA; f34->v7.image = fw->data; @@ -1376,8 +1378,13 @@ int rmi_f34v7_probe(struct f34_data *f34) memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount)); memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr)); - rmi_f34v7_read_queries(f34); - f34->v7.force_update = false; + init_completion(&f34->v7.cmd_done); + + ret = rmi_f34v7_read_queries(f34); + if (ret < 0) + return ret; + + f34->v7.force_update = true; return 0; } -- cgit From 8b3afdfa48c70144479a2a5ca51a66e96ec60934 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 19 Apr 2017 08:47:06 -0700 Subject: Input: xen-kbdfront - add module parameter for setting resolution Add a parameter for setting the resolution of xen-kbdfront in order to be able to cope with a (virtual) frame buffer of arbitrary resolution. While at it remove the pointless second reading of parameters from Xenstore in the device connection phase: all parameters are available during device probing already and that is where they should be read. Signed-off-by: Juergen Gross Signed-off-by: Dmitry Torokhov --- drivers/input/misc/xen-kbdfront.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 1fd911d4fadf..690148f9940e 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -41,6 +41,12 @@ struct xenkbd_info { char phys[32]; }; +enum { KPARAM_X, KPARAM_Y, KPARAM_CNT }; +static int ptr_size[KPARAM_CNT] = { XENFB_WIDTH, XENFB_HEIGHT }; +module_param_array(ptr_size, int, NULL, 0444); +MODULE_PARM_DESC(ptr_size, + "Pointing device width, height in pixels (default 800,600)"); + static int xenkbd_remove(struct xenbus_device *); static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); static void xenkbd_disconnect_backend(struct xenkbd_info *); @@ -128,7 +134,12 @@ static int xenkbd_probe(struct xenbus_device *dev, if (!info->page) goto error_nomem; + /* Set input abs params to match backend screen res */ abs = xenbus_read_unsigned(dev->otherend, "feature-abs-pointer", 0); + ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, "width", + ptr_size[KPARAM_X]); + ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, "height", + ptr_size[KPARAM_Y]); if (abs) { ret = xenbus_write(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); @@ -174,8 +185,8 @@ static int xenkbd_probe(struct xenbus_device *dev, if (abs) { __set_bit(EV_ABS, ptr->evbit); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0); } else { input_set_capability(ptr, EV_REL, REL_X); input_set_capability(ptr, EV_REL, REL_Y); @@ -309,9 +320,6 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info) static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int ret, val; - switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: @@ -321,15 +329,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, break; case XenbusStateInitWait: -InitWait: - if (xenbus_read_unsigned(info->xbdev->otherend, - "feature-abs-pointer", 0)) { - ret = xenbus_write(XBT_NIL, info->xbdev->nodename, - "request-abs-pointer", "1"); - if (ret) - pr_warn("xenkbd: can't request abs-pointer\n"); - } - xenbus_switch_state(dev, XenbusStateConnected); break; @@ -340,17 +339,7 @@ InitWait: * get Connected twice here. */ if (dev->state != XenbusStateConnected) - goto InitWait; /* no InitWait seen yet, fudge it */ - - /* Set input abs params to match backend screen res */ - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "width", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); - - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "height", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); - + xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosed: -- cgit From e55057e82ad413603fd45eac3b83b80acde780e1 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Fri, 28 Apr 2017 09:58:12 -0700 Subject: Input: ar1021_i2c - enable touch mode during open The device could as well be in command mode, in which this driver cannot handle the device. When opening the device, let's make sure the device will be in the mode we expect it to be for this driver. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ar1021_i2c.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 1a94d8bfec54..21c74ee59341 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -18,6 +18,10 @@ #define AR1021_MAX_X 4095 #define AR1021_MAX_Y 4095 +#define AR1021_CMD 0x55 + +#define AR1021_CMD_ENABLE_TOUCH 0x12 + struct ar1021_i2c { struct i2c_client *client; struct input_dev *input; @@ -56,8 +60,19 @@ out: static int ar1021_i2c_open(struct input_dev *dev) { + static const u8 cmd_enable_touch[] = { + AR1021_CMD, + 0x01, /* number of bytes after this */ + AR1021_CMD_ENABLE_TOUCH + }; struct ar1021_i2c *ar1021 = input_get_drvdata(dev); struct i2c_client *client = ar1021->client; + int error; + + error = i2c_master_send(ar1021->client, cmd_enable_touch, + sizeof(cmd_enable_touch)); + if (error < 0) + return error; enable_irq(client->irq); -- cgit From 3071e9dd6cd3f2290d770117330f2c8b2e9a97e4 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 28 Apr 2017 10:25:51 -0700 Subject: Input: twl4030-pwrbutton - use correct device for irq request The interrupt should be requested for the platform device and not for the input device. Fixes: 7f9ce649d267 ("Input: twl4030-pwrbutton - simplify driver using devm_*") Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/twl4030-pwrbutton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 54162d2cbcfc..7c4504c31b07 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -70,7 +70,7 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev) pwr->phys = "twl4030_pwrbutton/input0"; pwr->dev.parent = &pdev->dev; - err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq, + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, powerbutton_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_pwrbutton", pwr); -- cgit From 61e29ec1c96f67605217c2a80441a75ff906db62 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 28 Apr 2017 10:27:37 -0700 Subject: Input: twl4030-pwrbutton - use input_set_capability() helper Cleanup driver slightly by using input_set_capability() instead of manually setting the required bits. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/misc/twl4030-pwrbutton.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 7c4504c31b07..1c13005b228f 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -64,8 +64,7 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev) return -ENOMEM; } - pwr->evbit[0] = BIT_MASK(EV_KEY); - pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + input_set_capability(pwr, EV_KEY, KEY_POWER); pwr->name = "twl4030_pwrbutton"; pwr->phys = "twl4030_pwrbutton/input0"; pwr->dev.parent = &pdev->dev; -- cgit From 8a038b83e012097a7ac6cfb9f6c5fac1da8fad6e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 1 May 2017 10:13:47 -0700 Subject: Input: ar1021_i2c - use BIT to check for a bit The MSB for the first byte of touch data transmission is always 1. Make it a little more obvious we're testing this bit by using BIT(7). Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ar1021_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 21c74ee59341..f9dcbd63e598 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -6,6 +6,7 @@ * License: GPLv2 as published by the FSF. */ +#include #include #include #include @@ -42,7 +43,7 @@ static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id) goto out; /* sync bit set ? */ - if ((data[0] & 0x80) == 0) + if (!(data[0] & BIT(7))) goto out; button = data[0] & BIT(0); -- cgit