diff options
Diffstat (limited to 'drivers/input')
49 files changed, 1716 insertions, 511 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index e494295d1c7b..95f90699d2b1 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -28,7 +28,6 @@ struct evdev { int open; struct input_handle handle; - wait_queue_head_t wait; struct evdev_client __rcu *grab; struct list_head client_list; spinlock_t client_lock; /* protects client_list */ @@ -43,6 +42,7 @@ struct evdev_client { unsigned int tail; unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ + wait_queue_head_t wait; struct fasync_struct *fasync; struct evdev *evdev; struct list_head node; @@ -245,7 +245,6 @@ static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t *ev_time) { - struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; struct timespec64 ts; @@ -282,7 +281,7 @@ static void evdev_pass_values(struct evdev_client *client, spin_unlock(&client->buffer_lock); if (wakeup) - wake_up_interruptible_poll(&evdev->wait, + wake_up_interruptible_poll(&client->wait, EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); } @@ -426,11 +425,11 @@ static void evdev_hangup(struct evdev *evdev) struct evdev_client *client; spin_lock(&evdev->client_lock); - list_for_each_entry(client, &evdev->client_list, node) + list_for_each_entry(client, &evdev->client_list, node) { kill_fasync(&client->fasync, SIGIO, POLL_HUP); + wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); + } spin_unlock(&evdev->client_lock); - - wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); } static int evdev_release(struct inode *inode, struct file *file) @@ -479,6 +478,7 @@ static int evdev_open(struct inode *inode, struct file *file) if (!client) return -ENOMEM; + init_waitqueue_head(&client->wait); client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); client->evdev = evdev; @@ -595,7 +595,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, break; if (!(file->f_flags & O_NONBLOCK)) { - error = wait_event_interruptible(evdev->wait, + error = wait_event_interruptible(client->wait, client->packet_head != client->tail || !evdev->exist || client->revoked); if (error) @@ -613,7 +613,7 @@ static __poll_t evdev_poll(struct file *file, poll_table *wait) struct evdev *evdev = client->evdev; __poll_t mask; - poll_wait(file, &evdev->wait, wait); + poll_wait(file, &client->wait, wait); if (evdev->exist && !client->revoked) mask = EPOLLOUT | EPOLLWRNORM; @@ -946,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, client->revoked = true; evdev_ungrab(evdev, client); input_flush_device(&evdev->handle, file); - wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); + wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR); return 0; } @@ -1358,7 +1358,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); - init_waitqueue_head(&evdev->wait); evdev->exist = true; dev_no = minor; diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index f699538bdac4..44fe6f2f063c 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -323,11 +323,14 @@ static int adjust_dual(int *begin, int step, int *end, int eq, int mu) p = begin + step; s = p == end ? f + 1 : *p; - for (; p != end; p += step) - if (*p < f) - s = f, f = *p; - else if (*p < s) + for (; p != end; p += step) { + if (*p < f) { + s = f; + f = *p; + } else if (*p < s) { s = *p; + } + } c = (f + s + 1) / 2; if (c == 0 || (c > mu && (!eq || mu > 0))) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index eb031b7a4866..b080f0cfb068 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -42,6 +42,16 @@ config JOYSTICK_A3D To compile this driver as a module, choose M here: the module will be called a3d. +config JOYSTICK_ADC + tristate "Simple joystick connected over ADC" + depends on IIO + select IIO_BUFFER_CB + help + Say Y here if you have a simple joystick connected over ADC. + + To compile this driver as a module, choose M here: the + module will be called adc-joystick. + config JOYSTICK_ADI tristate "Logitech ADI digital joysticks and gamepads" select GAMEPORT diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile index 8656023f6ef5..58232b3057d3 100644 --- a/drivers/input/joystick/Makefile +++ b/drivers/input/joystick/Makefile @@ -6,6 +6,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_JOYSTICK_A3D) += a3d.o +obj-$(CONFIG_JOYSTICK_ADC) += adc-joystick.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o diff --git a/drivers/input/joystick/adc-joystick.c b/drivers/input/joystick/adc-joystick.c new file mode 100644 index 000000000000..78ebca7d400a --- /dev/null +++ b/drivers/input/joystick/adc-joystick.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Input driver for joysticks connected over ADC. + * Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu> + */ +#include <linux/ctype.h> +#include <linux/input.h> +#include <linux/iio/iio.h> +#include <linux/iio/consumer.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/property.h> + +#include <asm/unaligned.h> + +struct adc_joystick_axis { + u32 code; + s32 range[2]; + s32 fuzz; + s32 flat; +}; + +struct adc_joystick { + struct input_dev *input; + struct iio_cb_buffer *buffer; + struct adc_joystick_axis *axes; + struct iio_channel *chans; + int num_chans; +}; + +static int adc_joystick_handle(const void *data, void *private) +{ + struct adc_joystick *joy = private; + enum iio_endian endianness; + int bytes, msb, val, idx, i; + const u16 *data_u16; + bool sign; + + bytes = joy->chans[0].channel->scan_type.storagebits >> 3; + + for (i = 0; i < joy->num_chans; ++i) { + idx = joy->chans[i].channel->scan_index; + endianness = joy->chans[i].channel->scan_type.endianness; + msb = joy->chans[i].channel->scan_type.realbits - 1; + sign = tolower(joy->chans[i].channel->scan_type.sign) == 's'; + + switch (bytes) { + case 1: + val = ((const u8 *)data)[idx]; + break; + case 2: + data_u16 = (const u16 *)data + idx; + + /* + * Data is aligned to the sample size by IIO core. + * Call `get_unaligned_xe16` to hide type casting. + */ + if (endianness == IIO_BE) + val = get_unaligned_be16(data_u16); + else if (endianness == IIO_LE) + val = get_unaligned_le16(data_u16); + else /* IIO_CPU */ + val = *data_u16; + break; + default: + return -EINVAL; + } + + val >>= joy->chans[i].channel->scan_type.shift; + if (sign) + val = sign_extend32(val, msb); + else + val &= GENMASK(msb, 0); + input_report_abs(joy->input, joy->axes[i].code, val); + } + + input_sync(joy->input); + + return 0; +} + +static int adc_joystick_open(struct input_dev *dev) +{ + struct adc_joystick *joy = input_get_drvdata(dev); + struct device *devp = &dev->dev; + int ret; + + ret = iio_channel_start_all_cb(joy->buffer); + if (ret) + dev_err(devp, "Unable to start callback buffer: %d\n", ret); + + return ret; +} + +static void adc_joystick_close(struct input_dev *dev) +{ + struct adc_joystick *joy = input_get_drvdata(dev); + + iio_channel_stop_all_cb(joy->buffer); +} + +static void adc_joystick_cleanup(void *data) +{ + iio_channel_release_all_cb(data); +} + +static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy) +{ + struct adc_joystick_axis *axes; + struct fwnode_handle *child; + int num_axes, error, i; + + num_axes = device_get_child_node_count(dev); + if (!num_axes) { + dev_err(dev, "Unable to find child nodes\n"); + return -EINVAL; + } + + if (num_axes != joy->num_chans) { + dev_err(dev, "Got %d child nodes for %d channels\n", + num_axes, joy->num_chans); + return -EINVAL; + } + + axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL); + if (!axes) + return -ENOMEM; + + device_for_each_child_node(dev, child) { + error = fwnode_property_read_u32(child, "reg", &i); + if (error) { + dev_err(dev, "reg invalid or missing\n"); + goto err_fwnode_put; + } + + if (i >= num_axes) { + error = -EINVAL; + dev_err(dev, "No matching axis for reg %d\n", i); + goto err_fwnode_put; + } + + error = fwnode_property_read_u32(child, "linux,code", + &axes[i].code); + if (error) { + dev_err(dev, "linux,code invalid or missing\n"); + goto err_fwnode_put; + } + + error = fwnode_property_read_u32_array(child, "abs-range", + axes[i].range, 2); + if (error) { + dev_err(dev, "abs-range invalid or missing\n"); + goto err_fwnode_put; + } + + fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz); + fwnode_property_read_u32(child, "abs-flat", &axes[i].flat); + + input_set_abs_params(joy->input, axes[i].code, + axes[i].range[0], axes[i].range[1], + axes[i].fuzz, axes[i].flat); + input_set_capability(joy->input, EV_ABS, axes[i].code); + } + + joy->axes = axes; + + return 0; + +err_fwnode_put: + fwnode_handle_put(child); + return error; +} + +static int adc_joystick_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adc_joystick *joy; + struct input_dev *input; + int error; + int bits; + int i; + + joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL); + if (!joy) + return -ENOMEM; + + joy->chans = devm_iio_channel_get_all(dev); + if (IS_ERR(joy->chans)) { + error = PTR_ERR(joy->chans); + if (error != -EPROBE_DEFER) + dev_err(dev, "Unable to get IIO channels"); + return error; + } + + /* Count how many channels we got. NULL terminated. */ + for (i = 0; joy->chans[i].indio_dev; i++) { + bits = joy->chans[i].channel->scan_type.storagebits; + if (!bits || bits > 16) { + dev_err(dev, "Unsupported channel storage size\n"); + return -EINVAL; + } + if (bits != joy->chans[0].channel->scan_type.storagebits) { + dev_err(dev, "Channels must have equal storage size\n"); + return -EINVAL; + } + } + joy->num_chans = i; + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "Unable to allocate input device\n"); + return -ENOMEM; + } + + joy->input = input; + input->name = pdev->name; + input->id.bustype = BUS_HOST; + input->open = adc_joystick_open; + input->close = adc_joystick_close; + + error = adc_joystick_set_axes(dev, joy); + if (error) + return error; + + input_set_drvdata(input, joy); + error = input_register_device(input); + if (error) { + dev_err(dev, "Unable to register input device\n"); + return error; + } + + joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy); + if (IS_ERR(joy->buffer)) { + dev_err(dev, "Unable to allocate callback buffer\n"); + return PTR_ERR(joy->buffer); + } + + error = devm_add_action_or_reset(dev, adc_joystick_cleanup, joy->buffer); + if (error) { + dev_err(dev, "Unable to add action\n"); + return error; + } + + return 0; +} + +static const struct of_device_id adc_joystick_of_match[] = { + { .compatible = "adc-joystick", }, + { } +}; +MODULE_DEVICE_TABLE(of, adc_joystick_of_match); + +static struct platform_driver adc_joystick_driver = { + .driver = { + .name = "adc-joystick", + .of_match_table = adc_joystick_of_match, + }, + .probe = adc_joystick_probe, +}; +module_platform_driver(adc_joystick_driver); + +MODULE_DESCRIPTION("Input driver for joysticks connected over ADC"); +MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index 2b625ebef914..f798922a4598 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -665,7 +665,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv int err; if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL))) - return - ENOMEM; + return -ENOMEM; err = analog_init_port(gameport, drv, port); if (err) diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index fc1793ca2f17..023f083dadd3 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -27,7 +27,9 @@ #include <asm/unaligned.h> -/* +/** + * struct cros_ec_keyb - Structure representing EC keyboard device + * * @rows: Number of rows in the keypad * @cols: Number of columns in the keypad * @row_shift: log2 or number of rows, rounded up @@ -58,10 +60,9 @@ struct cros_ec_keyb { struct notifier_block notifier; }; - /** - * cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap - * #defines + * struct cros_ec_bs_map - Mapping between Linux keycodes and EC button/switch + * bitmap #defines * * @ev_type: The type of the input event to generate (e.g., EV_KEY). * @code: A linux keycode diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 7c70492d9d6b..f831f01501d5 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -250,8 +250,8 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) } keypad->irq = platform_get_irq(pdev, 0); - if (!keypad->irq) { - err = -ENXIO; + if (keypad->irq < 0) { + err = keypad->irq; goto failed_free; } diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index f2d4e4daa818..a079504e98e8 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -108,7 +108,7 @@ static int get_n_events_by_type(int type) /** * get_bm_events_by_type() - returns bitmap of supported events per @type - * @input: input device from which bitmap is retrieved + * @dev: input device from which bitmap is retrieved * @type: type of button (%EV_KEY, %EV_SW) * * Return value of this function can be used to allocate bitmap diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 608446e14614..0d55a95347f1 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -58,6 +58,8 @@ * @board: keypad platform device * @keymap: matrix scan code table for keycodes * @clk: clock structure pointer + * @pclk: clock structure pointer + * @ske_keypad_lock: spinlock protecting the keypad read/writes */ struct ske_keypad { int irq; diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 94c94d7f5155..d6c924032aaa 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -240,10 +240,8 @@ static int omap4_keypad_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "no keyboard irq assigned\n"); - return -EINVAL; - } + if (irq < 0) + return irq; keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); if (!keypad_data) { diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 91d5811d6f0e..36bee6f5a8af 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -76,17 +76,17 @@ /** * struct pmic8xxx_kp - internal keypad data structure - * @num_cols - number of columns of keypad - * @num_rows - number of row of keypad - * @input - input device pointer for keypad - * @regmap - regmap handle - * @key_sense_irq - key press/release irq number - * @key_stuck_irq - key stuck notification irq number - * @keycodes - array to hold the key codes - * @dev - parent device pointer - * @keystate - present key press/release state - * @stuckstate - present state when key stuck irq - * @ctrl_reg - control register value + * @num_cols: number of columns of keypad + * @num_rows: number of row of keypad + * @input: input device pointer for keypad + * @regmap: regmap handle + * @key_sense_irq: key press/release irq number + * @key_stuck_irq: key stuck notification irq number + * @keycodes: array to hold the key codes + * @dev: parent device pointer + * @keystate: present key press/release state + * @stuckstate: present state when key stuck irq + * @ctrl_reg: control register value */ struct pmic8xxx_kp { unsigned int num_rows; diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 70c1d086bdd2..1ed939d9798c 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -146,13 +146,12 @@ static irqreturn_t samsung_keypad_irq(int irq, void *dev_id) { struct samsung_keypad *keypad = dev_id; unsigned int row_state[SAMSUNG_MAX_COLS]; - unsigned int val; bool key_down; pm_runtime_get_sync(&keypad->pdev->dev); do { - val = readl(keypad->base + SAMSUNG_KEYIFSTSCLR); + readl(keypad->base + SAMSUNG_KEYIFSTSCLR); /* Clear interrupt. */ writel(~0x0, keypad->base + SAMSUNG_KEYIFSTSCLR); diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index af3a6824f1a4..77e0743a3cf8 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -50,7 +50,7 @@ struct twl4030_keypad { bool autorepeat; unsigned int n_rows; unsigned int n_cols; - unsigned int irq; + int irq; struct device *dbg_dev; struct input_dev *input; @@ -376,10 +376,8 @@ static int twl4030_kp_probe(struct platform_device *pdev) } kp->irq = platform_get_irq(pdev, 0); - if (!kp->irq) { - dev_err(&pdev->dev, "no keyboard irq assigned\n"); - return -EINVAL; - } + if (kp->irq < 0) + return kp->irq; error = matrix_keypad_build_keymap(keymap_data, NULL, TWL4030_MAX_ROWS, diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index ea3b8292acdd..a9b9013680d6 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -19,7 +19,7 @@ /** * struct ab8500_ponkey - ab8500 ponkey information - * @input_dev: pointer to input device + * @idev: pointer to input device * @ab8500: ab8500 parent * @irq_dbf: irq number for falling transition * @irq_dbr: irq number for rising transition diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 79d7fa710a71..cc51de7759a0 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -167,17 +167,17 @@ /** * struct drv260x_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @enable_gpio - Pointer to the gpio used for enable/disabling - * @regulator - Pointer to the regulator for the IC - * @magnitude - Magnitude of the vibration event - * @mode - The operating mode of the IC (LRA_NO_CAL, ERM or LRA) - * @library - The vibration library to be used - * @rated_voltage - The rated_voltage of the actuator - * @overdriver_voltage - The over drive voltage of the actuator + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @enable_gpio: Pointer to the gpio used for enable/disabling + * @regulator: Pointer to the regulator for the IC + * @magnitude: Magnitude of the vibration event + * @mode: The operating mode of the IC (LRA_NO_CAL, ERM or LRA) + * @library: The vibration library to be used + * @rated_voltage: The rated_voltage of the actuator + * @overdrive_voltage: The over drive voltage of the actuator **/ struct drv260x_data { struct input_dev *input_dev; @@ -234,12 +234,12 @@ static const struct reg_default drv260x_reg_defs[] = { #define DRV260X_DEF_RATED_VOLT 0x90 #define DRV260X_DEF_OD_CLAMP_VOLT 0x90 -/** +/* * Rated and Overdriver Voltages: * Calculated using the formula r = v * 255 / 5.6 * where r is what will be written to the register * and v is the rated or overdriver voltage of the actuator - **/ + */ static int drv260x_calculate_voltage(unsigned int voltage) { return (voltage * 255 / 5600); diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 918ad9c3fa81..0e65ab180f49 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -44,11 +44,11 @@ /** * struct drv2665_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @regulator - Pointer to the regulator for the IC + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @regulator: Pointer to the regulator for the IC */ struct drv2665_data { struct input_dev *input_dev; diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index bb9d5784df17..dc19eb6a8713 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -90,12 +90,14 @@ /** * struct drv2667_data - - * @input_dev - Pointer to the input device - * @client - Pointer to the I2C client - * @regmap - Register map of the device - * @work - Work item used to off load the enable/disable of the vibration - * @regulator - Pointer to the regulator for the IC - * @magnitude - Magnitude of the vibration event + * @input_dev: Pointer to the input device + * @client: Pointer to the I2C client + * @regmap: Register map of the device + * @work: Work item used to off load the enable/disable of the vibration + * @regulator: Pointer to the regulator for the IC + * @page: Page number + * @magnitude: Magnitude of the vibration event + * @frequency: Frequency of the vibration event **/ struct drv2667_data { struct input_dev *input_dev; diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index 08520b3a18b8..cae1a3fae83a 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/acpi.h> +#include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/gpio_keys.h> #include <linux/gpio.h> @@ -23,6 +24,7 @@ struct soc_button_info { unsigned int event_code; bool autorepeat; bool wakeup; + bool active_low; }; struct soc_device_data { @@ -42,22 +44,65 @@ struct soc_button_data { }; /* + * Some 2-in-1s which use the soc_button_array driver have this ugly issue in + * their DSDT where the _LID method modifies the irq-type settings of the GPIOs + * used for the power and home buttons. The intend of this AML code is to + * disable these buttons when the lid is closed. + * The AML does this by directly poking the GPIO controllers registers. This is + * problematic because when re-enabling the irq, which happens whenever _LID + * gets called with the lid open (e.g. on boot and on resume), it sets the + * irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the + * type to, and expects it to be, IRQ_TYPE_EDGE_BOTH. + * To work around this we don't set gpio_keys_button.gpio on these 2-in-1s, + * instead we get the irq for the GPIO ourselves, configure it as + * IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass + * the irq in gpio_keys_button.irq. Below is a list of affected devices. + */ +static const struct dmi_system_id dmi_use_low_level_irq[] = { + { + /* + * Acer Switch 10 SW5-012. _LID method messes with home- and + * power-button GPIO IRQ settings. When (re-)enabling the irq + * it ors in its own flags without clearing the previous set + * ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW | + * IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"), + }, + }, + { + /* + * Acer One S1003. _LID method messes with power-button GPIO + * IRQ settings, leading to a non working power-button. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"), + }, + }, + {} /* Terminating entry */ +}; + +/* * Get the Nth GPIO number from the ACPI object. */ -static int soc_button_lookup_gpio(struct device *dev, int acpi_index) +static int soc_button_lookup_gpio(struct device *dev, int acpi_index, + int *gpio_ret, int *irq_ret) { struct gpio_desc *desc; - int gpio; desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); if (IS_ERR(desc)) return PTR_ERR(desc); - gpio = desc_to_gpio(desc); + *gpio_ret = desc_to_gpio(desc); + *irq_ret = gpiod_to_irq(desc); gpiod_put(desc); - return gpio; + return 0; } static struct platform_device * @@ -69,9 +114,8 @@ soc_button_device_create(struct platform_device *pdev, struct platform_device *pd; struct gpio_keys_button *gpio_keys; struct gpio_keys_platform_data *gpio_keys_pdata; + int error, gpio, irq; int n_buttons = 0; - int gpio; - int error; for (info = button_info; info->name; info++) if (info->autorepeat == autorepeat) @@ -91,8 +135,8 @@ soc_button_device_create(struct platform_device *pdev, if (info->autorepeat != autorepeat) continue; - gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); - if (!gpio_is_valid(gpio)) { + error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq); + if (error || irq < 0) { /* * Skip GPIO if not present. Note we deliberately * ignore -EPROBE_DEFER errors here. On some devices @@ -107,10 +151,18 @@ soc_button_device_create(struct platform_device *pdev, continue; } + /* See dmi_use_low_level_irq[] comment */ + if (!autorepeat && dmi_check_system(dmi_use_low_level_irq)) { + irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW); + gpio_keys[n_buttons].irq = irq; + gpio_keys[n_buttons].gpio = -ENOENT; + } else { + gpio_keys[n_buttons].gpio = gpio; + } + gpio_keys[n_buttons].type = info->event_type; gpio_keys[n_buttons].code = info->event_code; - gpio_keys[n_buttons].gpio = gpio; - gpio_keys[n_buttons].active_low = 1; + gpio_keys[n_buttons].active_low = info->active_low; gpio_keys[n_buttons].desc = info->name; gpio_keys[n_buttons].wakeup = info->wakeup; /* These devices often use cheap buttons, use 50 ms debounce */ @@ -173,6 +225,7 @@ static int soc_button_parse_btn_desc(struct device *dev, } info->event_type = EV_KEY; + info->active_low = true; info->acpi_index = soc_button_get_acpi_object_int(&desc->package.elements[1]); upage = soc_button_get_acpi_object_int(&desc->package.elements[3]); @@ -383,11 +436,11 @@ static int soc_button_probe(struct platform_device *pdev) * Platforms" */ static const struct soc_button_info soc_button_PNP0C40[] = { - { "power", 0, EV_KEY, KEY_POWER, false, true }, - { "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, - { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, - { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false }, - { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false }, + { "power", 0, EV_KEY, KEY_POWER, false, true, true }, + { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true }, + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true }, + { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true }, + { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true }, { } }; @@ -395,6 +448,15 @@ static const struct soc_device_data soc_device_PNP0C40 = { .button_info = soc_button_PNP0C40, }; +static const struct soc_button_info soc_button_INT33D3[] = { + { "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false }, + { } +}; + +static const struct soc_device_data soc_device_INT33D3 = { + .button_info = soc_button_INT33D3, +}; + /* * Special device check for Surface Book 2 and Surface Pro (2017). * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned @@ -444,9 +506,9 @@ static int soc_device_check_MSHW0040(struct device *dev) * Obtained from DSDT/testing. */ static const struct soc_button_info soc_button_MSHW0040[] = { - { "power", 0, EV_KEY, KEY_POWER, false, true }, - { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, - { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false }, + { "power", 0, EV_KEY, KEY_POWER, false, true, true }, + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true }, + { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true }, { } }; @@ -457,6 +519,8 @@ static const struct soc_device_data soc_device_MSHW0040 = { static const struct acpi_device_id soc_button_acpi_match[] = { { "PNP0C40", (unsigned long)&soc_device_PNP0C40 }, + { "INT33D3", (unsigned long)&soc_device_INT33D3 }, + { "ID9001", (unsigned long)&soc_device_INT33D3 }, { "ACPI0011", 0 }, /* Microsoft Surface Devices (5th and 6th generation) */ diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index c675f156948b..dacf7c0e43f9 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -119,7 +119,7 @@ static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len, /** * cyapa_i2c_write - Execute i2c block data write operation * @cyapa: Handle to this driver - * @ret: Offset of the data to written in the register map + * @reg: Offset of the data to written in the register map * @len: number of bytes to write * @values: Data to be written * diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index bb3a63d1268d..5c37af994b5b 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -385,7 +385,7 @@ ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) return size; } -/** +/* * Return a negative errno code else zero on success. */ ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) @@ -435,7 +435,7 @@ static enum cyapa_pm_stage cyapa_get_pip_pm_state(struct cyapa *cyapa) return pm_stage; } -/** +/* * This function is aimed to dump all not read data in Gen5 trackpad * before send any command, otherwise, the interrupt line will be blocked. */ diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index c599e21a8478..65d21a050cea 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -34,7 +34,6 @@ #include <linux/completion.h> #include <linux/of.h> #include <linux/property.h> -#include <linux/input/elan-i2c-ids.h> #include <linux/regulator/consumer.h> #include <asm/unaligned.h> @@ -1413,6 +1412,7 @@ static const struct i2c_device_id elan_id[] = { MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI +#include <linux/input/elan-i2c-ids.h> MODULE_DEVICE_TABLE(acpi, elan_acpi_id); #endif diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 90f8765f9efc..47cd0e7f79bd 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1827,7 +1827,7 @@ static int elantech_create_smbus(struct psmouse *psmouse, leave_breadcrumbs); } -/** +/* * elantech_setup_smbus - called once the PS/2 devices are enumerated * and decides to instantiate a SMBus InterTouch device. */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 4b81b2d0fe06..82577095e175 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -179,12 +179,14 @@ static const char * const smbus_pnp_ids[] = { "LEN0093", /* T480 */ "LEN0096", /* X280 */ "LEN0097", /* X280 -> ALPS trackpoint */ - "LEN0099", /* X1 Extreme 1st */ + "LEN0099", /* X1 Extreme Gen 1 / P1 Gen 1 */ "LEN009b", /* T580 */ + "LEN0402", /* X1 Extreme Gen 2 / P1 Gen 2 */ "LEN200f", /* T450s */ "LEN2044", /* L470 */ "LEN2054", /* E480 */ "LEN2055", /* E580 */ + "LEN2068", /* T14 Gen 1 */ "SYN3052", /* HP EliteBook 840 G4 */ "SYN3221", /* HP 15-ay000 */ "SYN323d", /* HP Spectre X360 13-w013dx */ @@ -1752,7 +1754,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse, .kernel_tracking = false, .topbuttonpad = topbuttonpad, }, - .f30_data = { + .gpio_data = { .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c), .trackstick_buttons = !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10), diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index a212ff706f74..16119f760d11 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -100,6 +100,14 @@ config RMI4_F34 device via the firmware loader interface. This is triggered using a sysfs attribute. +config RMI4_F3A + bool "RMI4 Function 3A (GPIO)" + help + Say Y here if you want to add support for RMI4 function 3A. + + Function 3A provides GPIO support for RMI4 devices. This includes + support for buttons on TouchPads and ClickPads. + config RMI4_F54 bool "RMI4 Function 54 (Analog diagnostics)" depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index f17631656987..02f14c846861 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -10,6 +10,7 @@ rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o +rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index af706a583656..24f31a5c0e04 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -286,7 +286,7 @@ void rmi_unregister_function(struct rmi_function *fn) /** * rmi_register_function_handler - register a handler for an RMI function * @handler: RMI handler that should be registered. - * @module: pointer to module that implements the handler + * @owner: pointer to module that implements the handler * @mod_name: name of the module implementing the handler * * This function performs additional setup of RMI function handler and @@ -365,6 +365,9 @@ static struct rmi_function_handler *fn_handlers[] = { #ifdef CONFIG_RMI4_F34 &rmi_f34_handler, #endif +#ifdef CONFIG_RMI4_F3A + &rmi_f3a_handler, +#endif #ifdef CONFIG_RMI4_F54 &rmi_f54_handler, #endif diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 65bfaa95e193..1c6c6086c0e5 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -135,6 +135,7 @@ extern struct rmi_function_handler rmi_f11_handler; extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f30_handler; extern struct rmi_function_handler rmi_f34_handler; +extern struct rmi_function_handler rmi_f3a_handler; extern struct rmi_function_handler rmi_f54_handler; extern struct rmi_function_handler rmi_f55_handler; #endif diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index e623c956376e..d7603c50f864 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -103,13 +103,15 @@ struct f01_basic_properties { #define RMI_F01_CTRL0_CONFIGURED_BIT BIT(7) /** - * @ctrl0 - see the bit definitions above. - * @doze_interval - controls the interval between checks for finger presence - * when the touch sensor is in doze mode, in units of 10ms. - * @wakeup_threshold - controls the capacitance threshold at which the touch - * sensor will decide to wake up from that low power state. - * @doze_holdoff - controls how long the touch sensor waits after the last - * finger lifts before entering the doze state, in units of 100ms. + * struct f01_device_control - controls basic sensor functions + * + * @ctrl0: see the bit definitions above. + * @doze_interval: controls the interval between checks for finger presence + * when the touch sensor is in doze mode, in units of 10ms. + * @wakeup_threshold: controls the capacitance threshold at which the touch + * sensor will decide to wake up from that low power state. + * @doze_holdoff: controls how long the touch sensor waits after the last + * finger lifts before entering the doze state, in units of 100ms. */ struct f01_device_control { u8 ctrl0; diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index ffa39ab153f2..49ca9168685a 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -30,12 +30,12 @@ #define DEFAULT_MIN_ABS_MT_TRACKING_ID 1 #define DEFAULT_MAX_ABS_MT_TRACKING_ID 10 -/** A note about RMI4 F11 register structure. +/* + * A note about RMI4 F11 register structure. * - * The properties for - * a given sensor are described by its query registers. The number of query - * registers and the layout of their contents are described by the F11 device - * queries as well as the sensor query information. + * The properties for a given sensor are described by its query registers. The + * number of query registers and the layout of their contents are described by + * the F11 device queries as well as the sensor query information. * * Similarly, each sensor has control registers that govern its behavior. The * size and layout of the control registers for a given sensor can be determined @@ -62,8 +62,8 @@ /* maximum ABS_MT_POSITION displacement (in mm) */ #define DMAX 10 -/** - * @rezero - writing this to the F11 command register will cause the sensor to +/* + * Writing this to the F11 command register will cause the sensor to * calibrate to the current capacitive state. */ #define RMI_F11_REZERO 0x01 @@ -178,135 +178,157 @@ #define F11_UNIFORM_CLICKPAD 0x02 /** + * struct f11_2d_sensor_queries - describes sensor capabilities + * * Query registers 1 through 4 are always present. * - * @nr_fingers - describes the maximum number of fingers the 2-D sensor - * supports. - * @has_rel - the sensor supports relative motion reporting. - * @has_abs - the sensor supports absolute poition reporting. - * @has_gestures - the sensor supports gesture reporting. - * @has_sensitivity_adjust - the sensor supports a global sensitivity - * adjustment. - * @configurable - the sensor supports various configuration options. - * @num_of_x_electrodes - the maximum number of electrodes the 2-D sensor - * supports on the X axis. - * @num_of_y_electrodes - the maximum number of electrodes the 2-D sensor - * supports on the Y axis. - * @max_electrodes - the total number of X and Y electrodes that may be - * configured. + * @nr_fingers: describes the maximum number of fingers the 2-D sensor + * supports. + * @has_rel: the sensor supports relative motion reporting. + * @has_abs: the sensor supports absolute poition reporting. + * @has_gestures: the sensor supports gesture reporting. + * @has_sensitivity_adjust: the sensor supports a global sensitivity + * adjustment. + * @configurable: the sensor supports various configuration options. + * @nr_x_electrodes: the maximum number of electrodes the 2-D sensor + * supports on the X axis. + * @nr_y_electrodes: the maximum number of electrodes the 2-D sensor + * supports on the Y axis. + * @max_electrodes: the total number of X and Y electrodes that may be + * configured. * * Query 5 is present if the has_abs bit is set. * - * @abs_data_size - describes the format of data reported by the absolute - * data source. Only one format (the kind used here) is supported at this - * time. - * @has_anchored_finger - then the sensor supports the high-precision second - * finger tracking provided by the manual tracking and motion sensitivity - * options. - * @has_adjust_hyst - the difference between the finger release threshold and - * the touch threshold. - * @has_dribble - the sensor supports the generation of dribble interrupts, - * which may be enabled or disabled with the dribble control bit. - * @has_bending_correction - Bending related data registers 28 and 36, and - * control register 52..57 are present. - * @has_large_object_suppression - control register 58 and data register 28 - * exist. - * @has_jitter_filter - query 13 and control 73..76 exist. + * @abs_data_size: describes the format of data reported by the absolute + * data source. Only one format (the kind used here) is supported at this + * time. + * @has_anchored_finger: then the sensor supports the high-precision second + * finger tracking provided by the manual tracking and motion sensitivity + * options. + * @has_adj_hyst: the difference between the finger release threshold and + * the touch threshold. + * @has_dribble: the sensor supports the generation of dribble interrupts, + * which may be enabled or disabled with the dribble control bit. + * @has_bending_correction: Bending related data registers 28 and 36, and + * control register 52..57 are present. + * @has_large_object_suppression: control register 58 and data register 28 + * exist. + * @has_jitter_filter: query 13 and control 73..76 exist. + * + * Query 6 is present if the has_rel it is set. + * + * @f11_2d_query6: this register is reserved. * * Gesture information queries 7 and 8 are present if has_gestures bit is set. * - * @has_single_tap - a basic single-tap gesture is supported. - * @has_tap_n_hold - tap-and-hold gesture is supported. - * @has_double_tap - double-tap gesture is supported. - * @has_early_tap - early tap is supported and reported as soon as the finger - * lifts for any tap event that could be interpreted as either a single tap - * or as the first tap of a double-tap or tap-and-hold gesture. - * @has_flick - flick detection is supported. - * @has_press - press gesture reporting is supported. - * @has_pinch - pinch gesture detection is supported. - * @has_palm_det - the 2-D sensor notifies the host whenever a large conductive - * object such as a palm or a cheek touches the 2-D sensor. - * @has_rotate - rotation gesture detection is supported. - * @has_touch_shapes - TouchShapes are supported. A TouchShape is a fixed - * rectangular area on the sensor that behaves like a capacitive button. - * @has_scroll_zones - scrolling areas near the sensor edges are supported. - * @has_individual_scroll_zones - if 1, then 4 scroll zones are supported; - * if 0, then only two are supported. - * @has_mf_scroll - the multifinger_scrolling bit will be set when - * more than one finger is involved in a scrolling action. + * @has_single_tap: a basic single-tap gesture is supported. + * @has_tap_n_hold: tap-and-hold gesture is supported. + * @has_double_tap: double-tap gesture is supported. + * @has_early_tap: early tap is supported and reported as soon as the finger + * lifts for any tap event that could be interpreted as either a single + * tap or as the first tap of a double-tap or tap-and-hold gesture. + * @has_flick: flick detection is supported. + * @has_press: press gesture reporting is supported. + * @has_pinch: pinch gesture detection is supported. + * @has_chiral: chiral (circular) scrolling gesture detection is supported. + * @has_palm_det: the 2-D sensor notifies the host whenever a large conductive + * object such as a palm or a cheek touches the 2-D sensor. + * @has_rotate: rotation gesture detection is supported. + * @has_touch_shapes: TouchShapes are supported. A TouchShape is a fixed + * rectangular area on the sensor that behaves like a capacitive button. + * @has_scroll_zones: scrolling areas near the sensor edges are supported. + * @has_individual_scroll_zones: if 1, then 4 scroll zones are supported; + * if 0, then only two are supported. + * @has_mf_scroll: the multifinger_scrolling bit will be set when + * more than one finger is involved in a scrolling action. + * @has_mf_edge_motion: indicates whether multi-finger edge motion gesture + * is supported. + * @has_mf_scroll_inertia: indicates whether multi-finger scroll inertia + * feature is supported. * * Convenience for checking bytes in the gesture info registers. This is done * often enough that we put it here to declutter the conditionals * - * @query7_nonzero - true if none of the query 7 bits are set - * @query8_nonzero - true if none of the query 8 bits are set + * @query7_nonzero: true if none of the query 7 bits are set + * @query8_nonzero: true if none of the query 8 bits are set * * Query 9 is present if the has_query9 is set. * - * @has_pen - detection of a stylus is supported and registers F11_2D_Ctrl20 - * and F11_2D_Ctrl21 exist. - * @has_proximity - detection of fingers near the sensor is supported and - * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist. - * @has_palm_det_sensitivity - the sensor supports the palm detect sensitivity - * feature and register F11_2D_Ctrl27 exists. - * @has_two_pen_thresholds - is has_pen is also set, then F11_2D_Ctrl35 exists. - * @has_contact_geometry - the sensor supports the use of contact geometry to - * map absolute X and Y target positions and registers F11_2D_Data18 - * through F11_2D_Data27 exist. + * @has_pen: detection of a stylus is supported and registers F11_2D_Ctrl20 + * and F11_2D_Ctrl21 exist. + * @has_proximity: detection of fingers near the sensor is supported and + * registers F11_2D_Ctrl22 through F11_2D_Ctrl26 exist. + * @has_palm_det_sensitivity: the sensor supports the palm detect sensitivity + * feature and register F11_2D_Ctrl27 exists. + * @has_suppress_on_palm_detect: the device supports the large object detect + * suppression feature and register F11_2D_Ctrl27 exists. + * @has_two_pen_thresholds: if has_pen is also set, then F11_2D_Ctrl35 exists. + * @has_contact_geometry: the sensor supports the use of contact geometry to + * map absolute X and Y target positions and registers F11_2D_Data18 + * through F11_2D_Data27 exist. + * @has_pen_hover_discrimination: if has_pen is also set, then registers + * F11_2D_Data29 through F11_2D_Data31, F11_2D_Ctrl68.*, F11_2D_Ctrl69 + * and F11_2D_Ctrl72 exist. + * @has_pen_filters: if has_pen is also set, then registers F11_2D_Ctrl70 and + * F11_2D_Ctrl71 exist. * * Touch shape info (query 10) is present if has_touch_shapes is set. * - * @nr_touch_shapes - the total number of touch shapes supported. + * @nr_touch_shapes: the total number of touch shapes supported. * * Query 11 is present if the has_query11 bit is set in query 0. * - * @has_z_tuning - if set, the sensor supports Z tuning and registers - * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist. - * @has_algorithm_selection - controls choice of noise suppression algorithm - * @has_w_tuning - the sensor supports Wx and Wy scaling and registers - * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist. - * @has_pitch_info - the X and Y pitches of the sensor electrodes can be - * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist. - * @has_finger_size - the default finger width settings for the - * sensor can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44 - * exist. - * @has_segmentation_aggressiveness - the sensor’s ability to distinguish - * multiple objects close together can be configured and register F11_2D_Ctrl45 - * exists. - * @has_XY_clip - the inactive outside borders of the sensor can be - * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist. - * @has_drumming_filter - the sensor can be configured to distinguish - * between a fast flick and a quick drumming movement and registers - * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist. + * @has_z_tuning: if set, the sensor supports Z tuning and registers + * F11_2D_Ctrl29 through F11_2D_Ctrl33 exist. + * @has_algorithm_selection: controls choice of noise suppression algorithm + * @has_w_tuning: the sensor supports Wx and Wy scaling and registers + * F11_2D_Ctrl36 through F11_2D_Ctrl39 exist. + * @has_pitch_info: the X and Y pitches of the sensor electrodes can be + * configured and registers F11_2D_Ctrl40 and F11_2D_Ctrl41 exist. + * @has_finger_size: the default finger width settings for the sensor + * can be configured and registers F11_2D_Ctrl42 through F11_2D_Ctrl44 + * exist. + * @has_segmentation_aggressiveness: the sensor’s ability to distinguish + * multiple objects close together can be configured and register + * F11_2D_Ctrl45 exists. + * @has_XY_clip: the inactive outside borders of the sensor can be + * configured and registers F11_2D_Ctrl46 through F11_2D_Ctrl49 exist. + * @has_drumming_filter: the sensor can be configured to distinguish + * between a fast flick and a quick drumming movement and registers + * F11_2D_Ctrl50 and F11_2D_Ctrl51 exist. * * Query 12 is present if hasQuery12 bit is set. * - * @has_gapless_finger - control registers relating to gapless finger are - * present. - * @has_gapless_finger_tuning - additional control and data registers relating - * to gapless finger are present. - * @has_8bit_w - larger W value reporting is supported. - * @has_adjustable_mapping - TBD - * @has_info2 - the general info query14 is present - * @has_physical_props - additional queries describing the physical properties - * of the sensor are present. - * @has_finger_limit - indicates that F11 Ctrl 80 exists. - * @has_linear_coeff - indicates that F11 Ctrl 81 exists. + * @has_gapless_finger: control registers relating to gapless finger are + * present. + * @has_gapless_finger_tuning: additional control and data registers relating + * to gapless finger are present. + * @has_8bit_w: larger W value reporting is supported. + * @has_adjustable_mapping: TBD + * @has_info2: the general info query14 is present + * @has_physical_props: additional queries describing the physical properties + * of the sensor are present. + * @has_finger_limit: indicates that F11 Ctrl 80 exists. + * @has_linear_coeff_2: indicates that F11 Ctrl 81 exists. * * Query 13 is present if Query 5's has_jitter_filter bit is set. - * @jitter_window_size - used by Design Studio 4. - * @jitter_filter_type - used by Design Studio 4. + * + * @jitter_window_size: used by Design Studio 4. + * @jitter_filter_type: used by Design Studio 4. * * Query 14 is present if query 12's has_general_info2 flag is set. * - * @light_control - Indicates what light/led control features are present, if - * any. - * @is_clear - if set, this is a clear sensor (indicating direct pointing - * application), otherwise it's opaque (indicating indirect pointing). - * @clickpad_props - specifies if this is a clickpad, and if so what sort of - * mechanism it uses - * @mouse_buttons - specifies the number of mouse buttons present (if any). - * @has_advanced_gestures - advanced driver gestures are supported. + * @light_control: Indicates what light/led control features are present, + * if any. + * @is_clear: if set, this is a clear sensor (indicating direct pointing + * application), otherwise it's opaque (indicating indirect pointing). + * @clickpad_props: specifies if this is a clickpad, and if so what sort of + * mechanism it uses + * @mouse_buttons: specifies the number of mouse buttons present (if any). + * @has_advanced_gestures: advanced driver gestures are supported. + * + * @x_sensor_size_mm: size of the sensor in millimeters on the X axis. + * @y_sensor_size_mm: size of the sensor in millimeters on the Y axis. */ struct f11_2d_sensor_queries { /* query1 */ diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c index a90dad1d9ac7..35045f161dc2 100644 --- a/drivers/input/rmi4/rmi_f30.c +++ b/drivers/input/rmi4/rmi_f30.c @@ -168,17 +168,17 @@ static int rmi_f30_config(struct rmi_function *fn) rmi_get_platform_data(fn->rmi_dev); int error; - /* can happen if f30_data.disable is set */ + /* can happen if gpio_data.disable is set */ if (!f30) return 0; - if (pdata->f30_data.trackstick_buttons) { + if (pdata->gpio_data.trackstick_buttons) { /* Try [re-]establish link to F03. */ f30->f03 = rmi_find_function(fn->rmi_dev, 0x03); f30->trackstick_buttons = f30->f03 != NULL; } - if (pdata->f30_data.disable) { + if (pdata->gpio_data.disable) { drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask); } else { /* Write Control Register values back to device */ @@ -245,10 +245,10 @@ static int rmi_f30_map_gpios(struct rmi_function *fn, if (!rmi_f30_is_valid_button(i, f30->ctrl)) continue; - if (pdata->f30_data.trackstick_buttons && + if (pdata->gpio_data.trackstick_buttons && i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) { f30->gpioled_key_map[i] = trackstick_button++; - } else if (!pdata->f30_data.buttonpad || !button_mapped) { + } else if (!pdata->gpio_data.buttonpad || !button_mapped) { f30->gpioled_key_map[i] = button; input_set_capability(input, EV_KEY, button++); button_mapped = true; @@ -264,7 +264,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn, * but I am not sure, so use only the pdata info and the number of * mapped buttons. */ - if (pdata->f30_data.buttonpad || (button - BTN_LEFT == 1)) + if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1)) __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); return 0; @@ -372,7 +372,7 @@ static int rmi_f30_probe(struct rmi_function *fn) struct f30_data *f30; int error; - if (pdata->f30_data.disable) + if (pdata->gpio_data.disable) return 0; if (!drv_data->input) { diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index 74f7c6f214ff..8d7ec9d89b18 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -1364,9 +1364,14 @@ int rmi_f34v7_probe(struct f34_data *f34) f34->bl_version = 6; } else if (f34->bootloader_id[1] == 7) { f34->bl_version = 7; + } else if (f34->bootloader_id[1] == 8) { + f34->bl_version = 8; } else { - dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n", - __func__); + dev_err(&f34->fn->dev, + "%s: Unrecognized bootloader version: %d (%c) %d (%c)\n", + __func__, + f34->bootloader_id[0], f34->bootloader_id[0], + f34->bootloader_id[1], f34->bootloader_id[1]); return -EINVAL; } diff --git a/drivers/input/rmi4/rmi_f3a.c b/drivers/input/rmi4/rmi_f3a.c new file mode 100644 index 000000000000..0e8baed84dbb --- /dev/null +++ b/drivers/input/rmi4/rmi_f3a.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2020 Synaptics Incorporated + */ + +#include <linux/kernel.h> +#include <linux/rmi.h> +#include <linux/input.h> +#include <linux/slab.h> +#include "rmi_driver.h" + +#define RMI_F3A_MAX_GPIO_COUNT 128 +#define RMI_F3A_MAX_REG_SIZE DIV_ROUND_UP(RMI_F3A_MAX_GPIO_COUNT, 8) + +/* Defs for Query 0 */ +#define RMI_F3A_GPIO_COUNT 0x7F + +#define RMI_F3A_DATA_REGS_MAX_SIZE RMI_F3A_MAX_REG_SIZE + +#define TRACKSTICK_RANGE_START 3 +#define TRACKSTICK_RANGE_END 6 + +struct f3a_data { + /* Query Data */ + u8 gpio_count; + + u8 register_count; + + u8 data_regs[RMI_F3A_DATA_REGS_MAX_SIZE]; + u16 *gpio_key_map; + + struct input_dev *input; + + struct rmi_function *f03; + bool trackstick_buttons; +}; + +static void rmi_f3a_report_button(struct rmi_function *fn, + struct f3a_data *f3a, unsigned int button) +{ + u16 key_code = f3a->gpio_key_map[button]; + bool key_down = !(f3a->data_regs[0] & BIT(button)); + + if (f3a->trackstick_buttons && + button >= TRACKSTICK_RANGE_START && + button <= TRACKSTICK_RANGE_END) { + rmi_f03_overwrite_button(f3a->f03, key_code, key_down); + } else { + rmi_dbg(RMI_DEBUG_FN, &fn->dev, + "%s: call input report key (0x%04x) value (0x%02x)", + __func__, key_code, key_down); + input_report_key(f3a->input, key_code, key_down); + } +} + +static irqreturn_t rmi_f3a_attention(int irq, void *ctx) +{ + struct rmi_function *fn = ctx; + struct f3a_data *f3a = dev_get_drvdata(&fn->dev); + struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); + int error; + int i; + + if (drvdata->attn_data.data) { + if (drvdata->attn_data.size < f3a->register_count) { + dev_warn(&fn->dev, + "F3A interrupted, but data is missing\n"); + return IRQ_HANDLED; + } + memcpy(f3a->data_regs, drvdata->attn_data.data, + f3a->register_count); + drvdata->attn_data.data += f3a->register_count; + drvdata->attn_data.size -= f3a->register_count; + } else { + error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, + f3a->data_regs, f3a->register_count); + if (error) { + dev_err(&fn->dev, + "%s: Failed to read F3a data registers: %d\n", + __func__, error); + return IRQ_RETVAL(error); + } + } + + for (i = 0; i < f3a->gpio_count; i++) + if (f3a->gpio_key_map[i] != KEY_RESERVED) + rmi_f3a_report_button(fn, f3a, i); + if (f3a->trackstick_buttons) + rmi_f03_commit_buttons(f3a->f03); + + return IRQ_HANDLED; +} + +static int rmi_f3a_config(struct rmi_function *fn) +{ + struct f3a_data *f3a = dev_get_drvdata(&fn->dev); + struct rmi_driver *drv = fn->rmi_dev->driver; + const struct rmi_device_platform_data *pdata = + rmi_get_platform_data(fn->rmi_dev); + + if (!f3a) + return 0; + + if (pdata->gpio_data.trackstick_buttons) { + /* Try [re-]establish link to F03. */ + f3a->f03 = rmi_find_function(fn->rmi_dev, 0x03); + f3a->trackstick_buttons = f3a->f03 != NULL; + } + + drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); + + return 0; +} + +static bool rmi_f3a_is_valid_button(int button, struct f3a_data *f3a, + u8 *query1_regs, u8 *ctrl1_regs) +{ + /* gpio exist && direction input */ + return (query1_regs[0] & BIT(button)) && !(ctrl1_regs[0] & BIT(button)); +} + +static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a, + u8 *query1_regs, u8 *ctrl1_regs) +{ + const struct rmi_device_platform_data *pdata = + rmi_get_platform_data(fn->rmi_dev); + struct input_dev *input = f3a->input; + unsigned int button = BTN_LEFT; + unsigned int trackstick_button = BTN_LEFT; + bool button_mapped = false; + int i; + int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END); + + f3a->gpio_key_map = devm_kcalloc(&fn->dev, + button_count, + sizeof(f3a->gpio_key_map[0]), + GFP_KERNEL); + if (!f3a->gpio_key_map) { + dev_err(&fn->dev, "Failed to allocate gpio map memory.\n"); + return -ENOMEM; + } + + for (i = 0; i < button_count; i++) { + if (!rmi_f3a_is_valid_button(i, f3a, query1_regs, ctrl1_regs)) + continue; + + if (pdata->gpio_data.trackstick_buttons && + i >= TRACKSTICK_RANGE_START && + i < TRACKSTICK_RANGE_END) { + f3a->gpio_key_map[i] = trackstick_button++; + } else if (!pdata->gpio_data.buttonpad || !button_mapped) { + f3a->gpio_key_map[i] = button; + input_set_capability(input, EV_KEY, button++); + button_mapped = true; + } + } + input->keycode = f3a->gpio_key_map; + input->keycodesize = sizeof(f3a->gpio_key_map[0]); + input->keycodemax = f3a->gpio_count; + + if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1)) + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + + return 0; +} + +static int rmi_f3a_initialize(struct rmi_function *fn, struct f3a_data *f3a) +{ + u8 query1[RMI_F3A_MAX_REG_SIZE]; + u8 ctrl1[RMI_F3A_MAX_REG_SIZE]; + u8 buf; + int error; + + error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &buf); + if (error < 0) { + dev_err(&fn->dev, "Failed to read general info register: %d\n", + error); + return -ENODEV; + } + + f3a->gpio_count = buf & RMI_F3A_GPIO_COUNT; + f3a->register_count = DIV_ROUND_UP(f3a->gpio_count, 8); + + /* Query1 -> gpio exist */ + error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1, + query1, f3a->register_count); + if (error) { + dev_err(&fn->dev, "Failed to read query1 register\n"); + return error; + } + + /* Ctrl1 -> gpio direction */ + error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr + 1, + ctrl1, f3a->register_count); + if (error) { + dev_err(&fn->dev, "Failed to read control1 register\n"); + return error; + } + + error = rmi_f3a_map_gpios(fn, f3a, query1, ctrl1); + if (error) + return error; + + return 0; +} + +static int rmi_f3a_probe(struct rmi_function *fn) +{ + struct rmi_device *rmi_dev = fn->rmi_dev; + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); + struct f3a_data *f3a; + int error; + + if (!drv_data->input) { + dev_info(&fn->dev, "F3A: no input device found, ignoring\n"); + return -ENXIO; + } + + f3a = devm_kzalloc(&fn->dev, sizeof(*f3a), GFP_KERNEL); + if (!f3a) + return -ENOMEM; + + f3a->input = drv_data->input; + + error = rmi_f3a_initialize(fn, f3a); + if (error) + return error; + + dev_set_drvdata(&fn->dev, f3a); + return 0; +} + +struct rmi_function_handler rmi_f3a_handler = { + .driver = { + .name = "rmi4_f3a", + }, + .func = 0x3a, + .probe = rmi_f3a_probe, + .config = rmi_f3a_config, + .attention = rmi_f3a_attention, +}; diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 6b23e679606e..93b328c796c6 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -42,6 +42,8 @@ /** * enum rmi_f54_report_type - RMI4 F54 report types * + * @F54_REPORT_NONE: No Image Report. + * * @F54_8BIT_IMAGE: Normalized 8-Bit Image Report. The capacitance variance * from baseline for each pixel. * @@ -64,6 +66,10 @@ * Report. Set Low reference to its minimum value and high * references to its maximum value, then report the raw * capacitance for each pixel. + * + * @F54_MAX_REPORT_TYPE: + * Maximum number of Report Types. Used for sanity + * checking. */ enum rmi_f54_report_type { F54_REPORT_NONE = 0, diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index a95c2c9bcab4..50305fcfbef5 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -17,12 +17,16 @@ * struct rmi_i2c_xport - stores information for i2c communication * * @xport: The transport interface structure + * @client: The I2C client device structure * * @page_mutex: Locks current page to avoid changing pages in unexpected ways. * @page: Keeps track of the current virtual page * * @tx_buf: Buffer used for transmitting data to the sensor over i2c. * @tx_buf_size: Size of the buffer + * + * @supplies: Array of voltage regulators + * @startup_delay: Milliseconds to pause after powering up the regulators */ struct rmi_i2c_xport { struct rmi_transport_dev xport; diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c index a681a2c04e39..f15ed3dcdb9b 100644 --- a/drivers/input/serio/sun4i-ps2.c +++ b/drivers/input/serio/sun4i-ps2.c @@ -211,7 +211,6 @@ static int sun4i_ps2_probe(struct platform_device *pdev) struct sun4i_ps2data *drvdata; struct serio *serio; struct device *dev = &pdev->dev; - unsigned int irq; int error; drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL); @@ -264,14 +263,12 @@ static int sun4i_ps2_probe(struct platform_device *pdev) writel(0, drvdata->reg_base + PS2_REG_GCTL); /* Get IRQ for the device */ - irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(dev, "no IRQ found\n"); - error = -ENXIO; + drvdata->irq = platform_get_irq(pdev, 0); + if (drvdata->irq < 0) { + error = drvdata->irq; goto err_disable_clk; } - drvdata->irq = irq; drvdata->serio = serio; drvdata->dev = dev; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 35c867b2d9a7..f012fe746df0 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1322,4 +1322,16 @@ config TOUCHSCREEN_IQS5XX To compile this driver as a module, choose M here: the module will be called iqs5xx. +config TOUCHSCREEN_ZINITIX + tristate "Zinitix touchscreen support" + depends on I2C + help + Say Y here if you have a touchscreen using Zinitix bt541, + or something similar enough. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called zinitix. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 30d1e1b42492..6233541e9173 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -111,3 +111,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o +obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 8fd7fc39c4fd..de058644ef8a 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -32,7 +32,7 @@ #include <linux/spi/ads7846.h> #include <linux/regulator/consumer.h> #include <linux/module.h> -#include <asm/irq.h> +#include <asm/unaligned.h> /* * This code has been heavily tested on a Nokia 770, and lightly @@ -62,19 +62,26 @@ /* this driver doesn't aim at the peak continuous sample rate */ #define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */) -struct ts_event { +struct ads7846_buf { + u8 cmd; /* - * For portability, we can't read 12 bit values using SPI (which - * would make the controller deliver them as native byte order u16 - * with msbs zeroed). Instead, we read them as two 8-bit values, - * *** WHICH NEED BYTESWAPPING *** and range adjustment. + * This union is a temporary hack. The driver does an in-place + * endianness conversion. This will be cleaned up in the next + * patch. */ - u16 x; - u16 y; - u16 z1, z2; - bool ignore; - u8 x_buf[3]; - u8 y_buf[3]; + union { + __be16 data_be16; + u16 data; + }; +} __packed; + + +struct ts_event { + bool ignore; + struct ads7846_buf x; + struct ads7846_buf y; + struct ads7846_buf z1; + struct ads7846_buf z2; }; /* @@ -83,11 +90,12 @@ struct ts_event { * systems where main memory is not DMA-coherent (most non-x86 boards). */ struct ads7846_packet { - u8 read_x, read_y, read_z1, read_z2, pwrdown; - u16 dummy; /* for the pwrdown read */ - struct ts_event tc; - /* for ads7845 with mpc5121 psc spi we use 3-byte buffers */ - u8 read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3]; + struct ts_event tc; + struct ads7846_buf read_x_cmd; + struct ads7846_buf read_y_cmd; + struct ads7846_buf read_z1_cmd; + struct ads7846_buf read_z2_cmd; + struct ads7846_buf pwrdown_cmd; }; struct ads7846 { @@ -199,6 +207,26 @@ struct ads7846 { #define REF_ON (READ_12BIT_DFR(x, 1, 1)) #define REF_OFF (READ_12BIT_DFR(y, 0, 0)) +static int get_pendown_state(struct ads7846 *ts) +{ + if (ts->get_pendown_state) + return ts->get_pendown_state(); + + return !gpio_get_value(ts->gpio_pendown); +} + +static void ads7846_report_pen_up(struct ads7846 *ts) +{ + struct input_dev *input = ts->input; + + input_report_key(input, BTN_TOUCH, 0); + input_report_abs(input, ABS_PRESSURE, 0); + input_sync(input); + + ts->pendown = false; + dev_vdbg(&ts->spi->dev, "UP\n"); +} + /* Must be called with ts->lock held */ static void ads7846_stop(struct ads7846 *ts) { @@ -215,6 +243,10 @@ static void ads7846_stop(struct ads7846 *ts) static void ads7846_restart(struct ads7846 *ts) { if (!ts->disabled && !ts->suspended) { + /* Check if pen was released since last stop */ + if (ts->pendown && !get_pendown_state(ts)) + ads7846_report_pen_up(ts); + /* Tell IRQ thread that it may poll the device. */ ts->stopped = false; mb(); @@ -411,7 +443,7 @@ static int ads7845_read12_ser(struct device *dev, unsigned command) if (status == 0) { /* BE12 value, then padding */ - status = be16_to_cpu(*((u16 *)&req->sample[1])); + status = get_unaligned_be16(&req->sample[1]); status = status >> 3; status &= 0x0fff; } @@ -481,7 +513,7 @@ SHOW(in1_input, vbatt, vbatt_adjust) static umode_t ads7846_is_visible(struct kobject *kobj, struct attribute *attr, int index) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct ads7846 *ts = dev_get_drvdata(dev); if (ts->model == 7843 && index < 2) /* in0, in1 */ @@ -606,14 +638,6 @@ static const struct attribute_group ads784x_attr_group = { /*--------------------------------------------------------------------------*/ -static int get_pendown_state(struct ads7846 *ts) -{ - if (ts->get_pendown_state) - return ts->get_pendown_state(); - - return !gpio_get_value(ts->gpio_pendown); -} - static void null_wait_for_sync(void) { } @@ -670,16 +694,9 @@ static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) int value; struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + struct ads7846_buf *buf = t->rx_buf; - if (ts->model == 7845) { - value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1])); - } else { - /* - * adjust: on-wire is a must-ignore bit, a BE12 value, then - * padding; built from two 8 bit values written msb-first. - */ - value = be16_to_cpup((__be16 *)t->rx_buf); - } + value = be16_to_cpup(&buf->data_be16); /* enforce ADC output is 12 bits width */ return (value >> 3) & 0xfff; @@ -689,8 +706,9 @@ static void ads7846_update_value(struct spi_message *m, int val) { struct spi_transfer *t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + struct ads7846_buf *buf = t->rx_buf; - *(u16 *)t->rx_buf = val; + buf->data = val; } static void ads7846_read_state(struct ads7846 *ts) @@ -758,16 +776,14 @@ static void ads7846_report_state(struct ads7846 *ts) * from on-the-wire format as part of debouncing to get stable * readings. */ + x = packet->tc.x.data; + y = packet->tc.y.data; if (ts->model == 7845) { - x = *(u16 *)packet->tc.x_buf; - y = *(u16 *)packet->tc.y_buf; z1 = 0; z2 = 0; } else { - x = packet->tc.x; - y = packet->tc.y; - z1 = packet->tc.z1; - z2 = packet->tc.z2; + z1 = packet->tc.z1.data; + z2 = packet->tc.z2.data; } /* range filtering */ @@ -786,10 +802,11 @@ static void ads7846_report_state(struct ads7846 *ts) /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; - Rt *= x; Rt *= ts->x_plate_ohms; + Rt = DIV_ROUND_CLOSEST(Rt, 16); + Rt *= x; Rt /= z1; - Rt = (Rt + 2047) >> 12; + Rt = DIV_ROUND_CLOSEST(Rt, 256); } else { Rt = 0; } @@ -868,16 +885,8 @@ static irqreturn_t ads7846_irq(int irq, void *handle) msecs_to_jiffies(TS_POLL_PERIOD)); } - if (ts->pendown && !ts->stopped) { - struct input_dev *input = ts->input; - - input_report_key(input, BTN_TOUCH, 0); - input_report_abs(input, ABS_PRESSURE, 0); - input_sync(input); - - ts->pendown = false; - dev_vdbg(&ts->spi->dev, "UP\n"); - } + if (ts->pendown && !ts->stopped) + ads7846_report_pen_up(ts); return IRQ_HANDLED; } @@ -992,26 +1001,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - packet->read_y_cmd[0] = READ_Y(vref); - packet->read_y_cmd[1] = 0; - packet->read_y_cmd[2] = 0; - x->tx_buf = &packet->read_y_cmd[0]; - x->rx_buf = &packet->tc.y_buf[0]; - x->len = 3; - spi_message_add_tail(x, m); - } else { - /* y- still on; turn on only y+ (and ADC) */ - packet->read_y = READ_Y(vref); - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.y; - x->len = 2; - spi_message_add_tail(x, m); - } + packet->read_y_cmd.cmd = READ_Y(vref); + x->tx_buf = &packet->read_y_cmd; + x->rx_buf = &packet->tc.y; + x->len = 3; + spi_message_add_tail(x, m); /* * The first sample after switching drivers can be low quality; @@ -1021,15 +1015,11 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, if (pdata->settle_delay_usecs) { x->delay.value = pdata->settle_delay_usecs; x->delay.unit = SPI_DELAY_UNIT_USECS; - x++; - x->tx_buf = &packet->read_y; - x->len = 1; - spi_message_add_tail(x, m); - x++; + x->tx_buf = &packet->read_y_cmd; x->rx_buf = &packet->tc.y; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1038,28 +1028,13 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - x++; - packet->read_x_cmd[0] = READ_X(vref); - packet->read_x_cmd[1] = 0; - packet->read_x_cmd[2] = 0; - x->tx_buf = &packet->read_x_cmd[0]; - x->rx_buf = &packet->tc.x_buf[0]; - x->len = 3; - spi_message_add_tail(x, m); - } else { - /* turn y- off, x+ on, then leave in lowpower */ - x++; - packet->read_x = READ_X(vref); - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->tc.x; - x->len = 2; - spi_message_add_tail(x, m); - } + /* turn y- off, x+ on, then leave in lowpower */ + x++; + packet->read_x_cmd.cmd = READ_X(vref); + x->tx_buf = &packet->read_x_cmd; + x->rx_buf = &packet->tc.x; + x->len = 3; + spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ if (pdata->settle_delay_usecs) { @@ -1067,13 +1042,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_x; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_x_cmd; x->rx_buf = &packet->tc.x; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1085,14 +1056,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, m->context = ts; x++; - packet->read_z1 = READ_Z1(vref); - x->tx_buf = &packet->read_z1; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + packet->read_z1_cmd.cmd = READ_Z1(vref); + x->tx_buf = &packet->read_z1_cmd; x->rx_buf = &packet->tc.z1; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ @@ -1101,13 +1068,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_z1; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_z1_cmd; x->rx_buf = &packet->tc.z1; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } @@ -1117,14 +1080,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, m->context = ts; x++; - packet->read_z2 = READ_Z2(vref); - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + packet->read_z2_cmd.cmd = READ_Z2(vref); + x->tx_buf = &packet->read_z2_cmd; x->rx_buf = &packet->tc.z2; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); /* ... maybe discard first sample ... */ @@ -1133,13 +1092,9 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, x->delay.unit = SPI_DELAY_UNIT_USECS; x++; - x->tx_buf = &packet->read_z2; - x->len = 1; - spi_message_add_tail(x, m); - - x++; + x->tx_buf = &packet->read_z2_cmd; x->rx_buf = &packet->tc.z2; - x->len = 2; + x->len = 3; spi_message_add_tail(x, m); } } @@ -1150,24 +1105,10 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts, spi_message_init(m); m->context = ts; - if (ts->model == 7845) { - x++; - packet->pwrdown_cmd[0] = PWRDOWN; - packet->pwrdown_cmd[1] = 0; - packet->pwrdown_cmd[2] = 0; - x->tx_buf = &packet->pwrdown_cmd[0]; - x->len = 3; - } else { - x++; - packet->pwrdown = PWRDOWN; - x->tx_buf = &packet->pwrdown; - x->len = 1; - spi_message_add_tail(x, m); - - x++; - x->rx_buf = &packet->dummy; - x->len = 2; - } + x++; + packet->pwrdown_cmd.cmd = PWRDOWN; + x->tx_buf = &packet->pwrdown_cmd; + x->len = 3; CS_CHANGE(*x); spi_message_add_tail(x, m); diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 02a73d9a4def..dccbcb942fe5 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -30,6 +30,20 @@ #define CY_CORE_STARTUP_RETRY_COUNT 3 +static const char * const cyttsp4_tch_abs_string[] = { + [CY_TCH_X] = "X", + [CY_TCH_Y] = "Y", + [CY_TCH_P] = "P", + [CY_TCH_T] = "T", + [CY_TCH_E] = "E", + [CY_TCH_O] = "O", + [CY_TCH_W] = "W", + [CY_TCH_MAJ] = "MAJ", + [CY_TCH_MIN] = "MIN", + [CY_TCH_OR] = "OR", + [CY_TCH_NUM_ABS] = "INVALID" +}; + static const u8 ldr_exit[] = { 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17 }; diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h index f3e444359440..6262f6e45075 100644 --- a/drivers/input/touchscreen/cyttsp4_core.h +++ b/drivers/input/touchscreen/cyttsp4_core.h @@ -233,20 +233,6 @@ enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */ CY_TCH_NUM_ABS }; -static const char * const cyttsp4_tch_abs_string[] = { - [CY_TCH_X] = "X", - [CY_TCH_Y] = "Y", - [CY_TCH_P] = "P", - [CY_TCH_T] = "T", - [CY_TCH_E] = "E", - [CY_TCH_O] = "O", - [CY_TCH_W] = "W", - [CY_TCH_MAJ] = "MAJ", - [CY_TCH_MIN] = "MIN", - [CY_TCH_OR] = "OR", - [CY_TCH_NUM_ABS] = "INVALID" -}; - struct cyttsp4_touch { int abs[CY_TCH_NUM_ABS]; }; diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index eadd389cf81f..491de67ddbcd 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -28,6 +28,7 @@ #define EKTF2127_RESPONSE 0x52 #define EKTF2127_REQUEST 0x53 #define EKTF2127_HELLO 0x55 +#define EKTF2127_REPORT2 0x5a #define EKTF2127_REPORT 0x5d #define EKTF2127_CALIB_DONE 0x66 @@ -95,6 +96,29 @@ static void ektf2127_report_event(struct ektf2127_ts *ts, const u8 *buf) input_sync(ts->input); } +static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot, + const u8 *buf, bool active) +{ + input_mt_slot(ts->input, slot); + input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, active); + + if (active) { + int x = (buf[0] & 0xf0) << 4 | buf[1]; + int y = (buf[0] & 0x0f) << 8 | buf[2]; + + touchscreen_report_pos(ts->input, &ts->prop, x, y, true); + } +} + +static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf) +{ + ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2)); + ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4)); + + input_mt_sync_frame(ts->input); + input_sync(ts->input); +} + static irqreturn_t ektf2127_irq(int irq, void *dev_id) { struct ektf2127_ts *ts = dev_id; @@ -113,6 +137,10 @@ static irqreturn_t ektf2127_irq(int irq, void *dev_id) ektf2127_report_event(ts, buf); break; + case EKTF2127_REPORT2: + ektf2127_report2_event(ts, buf); + break; + case EKTF2127_NOISE: if (buf[1] == EKTF2127_ENV_NOISY) dev_dbg(dev, "Environment is electrically noisy\n"); @@ -305,6 +333,7 @@ static int ektf2127_probe(struct i2c_client *client, #ifdef CONFIG_OF static const struct of_device_id ektf2127_of_match[] = { { .compatible = "elan,ektf2127" }, + { .compatible = "elan,ektf2132" }, {} }; MODULE_DEVICE_TABLE(of, ektf2127_of_match); @@ -312,6 +341,7 @@ MODULE_DEVICE_TABLE(of, ektf2127_of_match); static const struct i2c_device_id ektf2127_i2c_id[] = { { "ektf2127", 0 }, + { "ektf2132", 0 }, {} }; MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id); @@ -327,6 +357,6 @@ static struct i2c_driver ektf2127_driver = { }; module_i2c_driver(ektf2127_driver); -MODULE_DESCRIPTION("ELAN eKTF2127 I2C Touchscreen Driver"); +MODULE_DESCRIPTION("ELAN eKTF2127/eKTF2132 I2C Touchscreen Driver"); MODULE_AUTHOR("Michel Verlaan, Siebren Vroegindeweij"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index b0bd5bb079be..50c348297e38 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -90,7 +90,7 @@ /* FW read command, 0x53 0x?? 0x0, 0x01 */ #define E_ELAN_INFO_FW_VER 0x00 #define E_ELAN_INFO_BC_VER 0x10 -#define E_ELAN_INFO_REK 0xE0 +#define E_ELAN_INFO_REK 0xD0 #define E_ELAN_INFO_TEST_VER 0xE0 #define E_ELAN_INFO_FW_ID 0xF0 #define E_INFO_OSR 0xD6 @@ -134,6 +134,7 @@ struct elants_data { u8 bc_version; u8 iap_version; u16 hw_version; + u8 major_res; unsigned int x_res; /* resolution in units/mm */ unsigned int y_res; unsigned int x_max; @@ -459,6 +460,9 @@ static int elants_i2c_query_ts_info(struct elants_data *ts) rows = resp[2] + resp[6] + resp[10]; cols = resp[3] + resp[7] + resp[11]; + /* Get report resolution value of ABS_MT_TOUCH_MAJOR */ + ts->major_res = resp[16]; + /* Process mm_to_pixel information */ error = elants_i2c_execute_command(client, get_osr_cmd, sizeof(get_osr_cmd), @@ -1325,6 +1329,8 @@ static int elants_i2c_probe(struct i2c_client *client, 0, MT_TOOL_PALM, 0, 0); input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); + if (ts->major_res > 0) + input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); touchscreen_parse_properties(ts->input, true, &ts->prop); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 9ed258854349..e1852f7d4d31 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -304,20 +304,18 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; u32 coco; - u32 value; coco = readl(tsc->adc_regs + REG_ADC_HS); if (coco & 0x01) { - value = readl(tsc->adc_regs + REG_ADC_R0); + readl(tsc->adc_regs + REG_ADC_R0); complete(&tsc->completion); } return IRQ_HANDLED; } -static int imx6ul_tsc_open(struct input_dev *input_dev) +static int imx6ul_tsc_start(struct imx6ul_tsc *tsc) { - struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); int err; err = clk_prepare_enable(tsc->adc_clk); @@ -349,16 +347,29 @@ disable_adc_clk: return err; } -static void imx6ul_tsc_close(struct input_dev *input_dev) +static void imx6ul_tsc_stop(struct imx6ul_tsc *tsc) { - struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); - imx6ul_tsc_disable(tsc); clk_disable_unprepare(tsc->tsc_clk); clk_disable_unprepare(tsc->adc_clk); } + +static int imx6ul_tsc_open(struct input_dev *input_dev) +{ + struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); + + return imx6ul_tsc_start(tsc); +} + +static void imx6ul_tsc_close(struct input_dev *input_dev) +{ + struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); + + imx6ul_tsc_stop(tsc); +} + static int imx6ul_tsc_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -509,12 +520,8 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) { - imx6ul_tsc_disable(tsc); - - clk_disable_unprepare(tsc->tsc_clk); - clk_disable_unprepare(tsc->adc_clk); - } + if (input_dev->users) + imx6ul_tsc_stop(tsc); mutex_unlock(&input_dev->mutex); @@ -530,22 +537,11 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev) mutex_lock(&input_dev->mutex); - if (input_dev->users) { - retval = clk_prepare_enable(tsc->adc_clk); - if (retval) - goto out; - - retval = clk_prepare_enable(tsc->tsc_clk); - if (retval) { - clk_disable_unprepare(tsc->adc_clk); - goto out; - } - - retval = imx6ul_tsc_init(tsc); - } + if (input_dev->users) + retval = imx6ul_tsc_start(tsc); -out: mutex_unlock(&input_dev->mutex); + return retval; } diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index fe245439adee..e694a9b2b1e5 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -51,6 +51,7 @@ /* Touch relative info */ #define RM_MAX_RETRIES 3 +#define RM_RETRY_DELAY_MS 20 #define RM_MAX_TOUCH_NUM 10 #define RM_BOOT_DELAY_MS 100 @@ -136,83 +137,82 @@ struct raydium_data { bool wake_irq_enabled; }; -static int raydium_i2c_send(struct i2c_client *client, - u8 addr, const void *data, size_t len) +static int raydium_i2c_xfer(struct i2c_client *client, + u32 addr, void *data, size_t len, bool is_read) { - u8 *buf; - int tries = 0; - int ret; - - buf = kmalloc(len + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - buf[0] = addr; - memcpy(buf + 1, data, len); - - do { - ret = i2c_master_send(client, buf, len + 1); - if (likely(ret == len + 1)) - break; - - msleep(20); - } while (++tries < RM_MAX_RETRIES); - - kfree(buf); - - if (unlikely(ret != len + 1)) { - if (ret >= 0) - ret = -EIO; - dev_err(&client->dev, "%s failed: %d\n", __func__, ret); - return ret; - } + struct raydium_bank_switch_header { + u8 cmd; + __be32 be_addr; + } __packed header = { + .cmd = RM_CMD_BANK_SWITCH, + .be_addr = cpu_to_be32(addr), + }; - return 0; -} + u8 reg_addr = addr & 0xff; -static int raydium_i2c_read(struct i2c_client *client, - u8 addr, void *data, size_t len) -{ struct i2c_msg xfer[] = { { .addr = client->addr, + .len = sizeof(header), + .buf = (u8 *)&header, + }, + { + .addr = client->addr, .len = 1, - .buf = &addr, + .buf = ®_addr, }, { .addr = client->addr, - .flags = I2C_M_RD, .len = len, .buf = data, + .flags = is_read ? I2C_M_RD : 0, } }; + + /* + * If address is greater than 255, then RM_CMD_BANK_SWITCH needs to be + * sent first. Else, skip the header i.e. xfer[0]. + */ + int xfer_start_idx = (addr > 0xff) ? 0 : 1; + size_t xfer_count = ARRAY_SIZE(xfer) - xfer_start_idx; int ret; - ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer)); - if (unlikely(ret != ARRAY_SIZE(xfer))) - return ret < 0 ? ret : -EIO; + ret = i2c_transfer(client->adapter, &xfer[xfer_start_idx], xfer_count); + if (likely(ret == xfer_count)) + return 0; + + return ret < 0 ? ret : -EIO; +} - return 0; +static int raydium_i2c_send(struct i2c_client *client, + u32 addr, const void *data, size_t len) +{ + int tries = 0; + int error; + + do { + error = raydium_i2c_xfer(client, addr, (void *)data, len, + false); + if (likely(!error)) + return 0; + + msleep(RM_RETRY_DELAY_MS); + } while (++tries < RM_MAX_RETRIES); + + dev_err(&client->dev, "%s failed: %d\n", __func__, error); + return error; } -static int raydium_i2c_read_message(struct i2c_client *client, - u32 addr, void *data, size_t len) +static int raydium_i2c_read(struct i2c_client *client, + u32 addr, void *data, size_t len) { - __be32 be_addr; size_t xfer_len; int error; while (len) { xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); - - be_addr = cpu_to_be32(addr); - - error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, - &be_addr, sizeof(be_addr)); - if (!error) - error = raydium_i2c_read(client, addr & 0xff, - data, xfer_len); - if (error) + error = raydium_i2c_xfer(client, addr, data, xfer_len, true); + if (unlikely(error)) return error; len -= xfer_len; @@ -223,27 +223,13 @@ static int raydium_i2c_read_message(struct i2c_client *client, return 0; } -static int raydium_i2c_send_message(struct i2c_client *client, - u32 addr, const void *data, size_t len) -{ - __be32 be_addr = cpu_to_be32(addr); - int error; - - error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH, - &be_addr, sizeof(be_addr)); - if (!error) - error = raydium_i2c_send(client, addr & 0xff, data, len); - - return error; -} - static int raydium_i2c_sw_reset(struct i2c_client *client) { const u8 soft_rst_cmd = 0x01; int error; - error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR, - &soft_rst_cmd, sizeof(soft_rst_cmd)); + error = raydium_i2c_send(client, RM_RESET_MSG_ADDR, &soft_rst_cmd, + sizeof(soft_rst_cmd)); if (error) { dev_err(&client->dev, "software reset failed: %d\n", error); return error; @@ -295,9 +281,8 @@ static int raydium_i2c_query_ts_info(struct raydium_data *ts) if (error) continue; - error = raydium_i2c_read_message(client, - le32_to_cpu(query_bank_addr), - &ts->info, sizeof(ts->info)); + error = raydium_i2c_read(client, le32_to_cpu(query_bank_addr), + &ts->info, sizeof(ts->info)); if (error) continue; @@ -834,8 +819,8 @@ static irqreturn_t raydium_i2c_irq(int irq, void *_dev) if (ts->boot_mode != RAYDIUM_TS_MAIN) goto out; - error = raydium_i2c_read_message(ts->client, ts->data_bank_addr, - ts->report_data, ts->pkg_size); + error = raydium_i2c_read(ts->client, ts->data_bank_addr, + ts->report_data, ts->pkg_size); if (error) goto out; diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index cfc8bb4553f7..e50af30183f4 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -23,7 +23,7 @@ #define GRTS_MAX_POS_MASK GENMASK(11, 0) /** - * grts_state - generic resistive touch screen information struct + * struct grts_state - generic resistive touch screen information struct * @pressure_min: number representing the minimum for the pressure * @pressure: are we getting pressure info or not * @iio_chans: list of channels acquired diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 63b29c7279e2..bda96762744e 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -26,15 +26,14 @@ #define ST1232_TS_NAME "st1232-ts" #define ST1633_TS_NAME "st1633-ts" +#define REG_XY_RESOLUTION 0x04 +#define REG_XY_COORDINATES 0x12 #define ST_TS_MAX_FINGERS 10 struct st_chip_info { bool have_z; - u16 max_x; - u16 max_y; u16 max_area; u16 max_fingers; - u8 start_reg; }; struct st1232_ts_data { @@ -48,15 +47,14 @@ struct st1232_ts_data { u8 *read_buf; }; -static int st1232_ts_read_data(struct st1232_ts_data *ts) +static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg) { struct i2c_client *client = ts->client; - u8 start_reg = ts->chip_info->start_reg; struct i2c_msg msg[] = { { .addr = client->addr, - .len = sizeof(start_reg), - .buf = &start_reg, + .len = sizeof(reg), + .buf = ®, }, { .addr = client->addr, @@ -74,6 +72,25 @@ static int st1232_ts_read_data(struct st1232_ts_data *ts) return 0; } +static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x, + u16 *max_y) +{ + u8 *buf; + int error; + + /* select resolution register */ + error = st1232_ts_read_data(ts, REG_XY_RESOLUTION); + if (error) + return error; + + buf = ts->read_buf; + + *max_x = ((buf[0] & 0x0070) << 4) | buf[1]; + *max_y = ((buf[0] & 0x0007) << 8) | buf[2]; + + return 0; +} + static int st1232_ts_parse_and_report(struct st1232_ts_data *ts) { struct input_dev *input = ts->input_dev; @@ -123,7 +140,7 @@ static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id) int count; int error; - error = st1232_ts_read_data(ts); + error = st1232_ts_read_data(ts, REG_XY_COORDINATES); if (error) goto out; @@ -157,20 +174,14 @@ static void st1232_ts_power_off(void *data) static const struct st_chip_info st1232_chip_info = { .have_z = true, - .max_x = 0x31f, /* 800 - 1 */ - .max_y = 0x1df, /* 480 -1 */ .max_area = 0xff, .max_fingers = 2, - .start_reg = 0x12, }; static const struct st_chip_info st1633_chip_info = { .have_z = false, - .max_x = 0x13f, /* 320 - 1 */ - .max_y = 0x1df, /* 480 -1 */ .max_area = 0x00, .max_fingers = 5, - .start_reg = 0x12, }; static int st1232_ts_probe(struct i2c_client *client, @@ -179,6 +190,7 @@ static int st1232_ts_probe(struct i2c_client *client, const struct st_chip_info *match; struct st1232_ts_data *ts; struct input_dev *input_dev; + u16 max_x, max_y; int error; match = device_get_match_data(&client->dev); @@ -239,14 +251,22 @@ static int st1232_ts_probe(struct i2c_client *client, input_dev->name = "st1232-touchscreen"; input_dev->id.bustype = BUS_I2C; + /* Read resolution from the chip */ + error = st1232_ts_read_resolution(ts, &max_x, &max_y); + if (error) { + dev_err(&client->dev, + "Failed to read resolution: %d\n", error); + return error; + } + if (ts->chip_info->have_z) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, ts->chip_info->max_area, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_X, - 0, ts->chip_info->max_x, 0, 0); + 0, max_x, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, - 0, ts->chip_info->max_y, 0, 0); + 0, max_y, 0, 0); touchscreen_parse_properties(input_dev, true, &ts->prop); diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index df946869d4cd..9a64e1dbc04a 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -479,7 +479,7 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, mutex_lock(&sdata->mutex); - if (value & sdata->hover_enabled) + if (value && sdata->hover_enabled) goto out; if (sdata->running) diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c new file mode 100644 index 000000000000..1acc2eb2bcb3 --- /dev/null +++ b/drivers/input/touchscreen/zinitix.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> + +/* Register Map */ + +#define BT541_SWRESET_CMD 0x0000 +#define BT541_WAKEUP_CMD 0x0001 + +#define BT541_IDLE_CMD 0x0004 +#define BT541_SLEEP_CMD 0x0005 + +#define BT541_CLEAR_INT_STATUS_CMD 0x0003 +#define BT541_CALIBRATE_CMD 0x0006 +#define BT541_SAVE_STATUS_CMD 0x0007 +#define BT541_SAVE_CALIBRATION_CMD 0x0008 +#define BT541_RECALL_FACTORY_CMD 0x000f + +#define BT541_THRESHOLD 0x0020 + +#define BT541_LARGE_PALM_REJECT_AREA_TH 0x003F + +#define BT541_DEBUG_REG 0x0115 /* 0~7 */ + +#define BT541_TOUCH_MODE 0x0010 +#define BT541_CHIP_REVISION 0x0011 +#define BT541_FIRMWARE_VERSION 0x0012 + +#define ZINITIX_USB_DETECT 0x116 + +#define BT541_MINOR_FW_VERSION 0x0121 + +#define BT541_VENDOR_ID 0x001C +#define BT541_HW_ID 0x0014 + +#define BT541_DATA_VERSION_REG 0x0013 +#define BT541_SUPPORTED_FINGER_NUM 0x0015 +#define BT541_EEPROM_INFO 0x0018 +#define BT541_INITIAL_TOUCH_MODE 0x0019 + +#define BT541_TOTAL_NUMBER_OF_X 0x0060 +#define BT541_TOTAL_NUMBER_OF_Y 0x0061 + +#define BT541_DELAY_RAW_FOR_HOST 0x007f + +#define BT541_BUTTON_SUPPORTED_NUM 0x00B0 +#define BT541_BUTTON_SENSITIVITY 0x00B2 +#define BT541_DUMMY_BUTTON_SENSITIVITY 0X00C8 + +#define BT541_X_RESOLUTION 0x00C0 +#define BT541_Y_RESOLUTION 0x00C1 + +#define BT541_POINT_STATUS_REG 0x0080 +#define BT541_ICON_STATUS_REG 0x00AA + +#define BT541_POINT_COORD_REG (BT541_POINT_STATUS_REG + 2) + +#define BT541_AFE_FREQUENCY 0x0100 +#define BT541_DND_N_COUNT 0x0122 +#define BT541_DND_U_COUNT 0x0135 + +#define BT541_RAWDATA_REG 0x0200 + +#define BT541_EEPROM_INFO_REG 0x0018 + +#define BT541_INT_ENABLE_FLAG 0x00f0 +#define BT541_PERIODICAL_INTERRUPT_INTERVAL 0x00f1 + +#define BT541_BTN_WIDTH 0x016d + +#define BT541_CHECKSUM_RESULT 0x012c + +#define BT541_INIT_FLASH 0x01d0 +#define BT541_WRITE_FLASH 0x01d1 +#define BT541_READ_FLASH 0x01d2 + +#define ZINITIX_INTERNAL_FLAG_02 0x011e +#define ZINITIX_INTERNAL_FLAG_03 0x011f + +#define ZINITIX_I2C_CHECKSUM_WCNT 0x016a +#define ZINITIX_I2C_CHECKSUM_RESULT 0x016c + +/* Interrupt & status register flags */ + +#define BIT_PT_CNT_CHANGE BIT(0) +#define BIT_DOWN BIT(1) +#define BIT_MOVE BIT(2) +#define BIT_UP BIT(3) +#define BIT_PALM BIT(4) +#define BIT_PALM_REJECT BIT(5) +#define BIT_RESERVED_0 BIT(6) +#define BIT_RESERVED_1 BIT(7) +#define BIT_WEIGHT_CHANGE BIT(8) +#define BIT_PT_NO_CHANGE BIT(9) +#define BIT_REJECT BIT(10) +#define BIT_PT_EXIST BIT(11) +#define BIT_RESERVED_2 BIT(12) +#define BIT_ERROR BIT(13) +#define BIT_DEBUG BIT(14) +#define BIT_ICON_EVENT BIT(15) + +#define SUB_BIT_EXIST BIT(0) +#define SUB_BIT_DOWN BIT(1) +#define SUB_BIT_MOVE BIT(2) +#define SUB_BIT_UP BIT(3) +#define SUB_BIT_UPDATE BIT(4) +#define SUB_BIT_WAIT BIT(5) + +#define DEFAULT_TOUCH_POINT_MODE 2 +#define MAX_SUPPORTED_FINGER_NUM 5 + +#define CHIP_ON_DELAY 15 // ms +#define FIRMWARE_ON_DELAY 40 // ms + +struct point_coord { + __le16 x; + __le16 y; + u8 width; + u8 sub_status; + // currently unused, but needed as padding: + u8 minor_width; + u8 angle; +}; + +struct touch_event { + __le16 status; + u8 finger_cnt; + u8 time_stamp; + struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM]; +}; + +struct bt541_ts_data { + struct i2c_client *client; + struct input_dev *input_dev; + struct touchscreen_properties prop; + struct regulator_bulk_data supplies[2]; + u32 zinitix_mode; +}; + +static int zinitix_read_data(struct i2c_client *client, + u16 reg, void *values, size_t length) +{ + __le16 reg_le = cpu_to_le16(reg); + int ret; + + /* A single i2c_transfer() transaction does not work here. */ + ret = i2c_master_send(client, (u8 *)®_le, sizeof(reg_le)); + if (ret != sizeof(reg_le)) + return ret < 0 ? ret : -EIO; + + ret = i2c_master_recv(client, (u8 *)values, length); + if (ret != length) + return ret < 0 ? ret : -EIO; ; + + return 0; +} + +static int zinitix_write_u16(struct i2c_client *client, u16 reg, u16 value) +{ + __le16 packet[2] = {cpu_to_le16(reg), cpu_to_le16(value)}; + int ret; + + ret = i2c_master_send(client, (u8 *)packet, sizeof(packet)); + if (ret != sizeof(packet)) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static int zinitix_write_cmd(struct i2c_client *client, u16 reg) +{ + __le16 reg_le = cpu_to_le16(reg); + int ret; + + ret = i2c_master_send(client, (u8 *)®_le, sizeof(reg_le)); + if (ret != sizeof(reg_le)) + return ret < 0 ? ret : -EIO; + + return 0; +} + +static bool zinitix_init_touch(struct bt541_ts_data *bt541) +{ + struct i2c_client *client = bt541->client; + int i; + int error; + + error = zinitix_write_cmd(client, BT541_SWRESET_CMD); + if (error) { + dev_err(&client->dev, "Failed to write reset command\n"); + return error; + } + + error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, 0x0); + if (error) { + dev_err(&client->dev, + "Failed to reset interrupt enable flag\n"); + return error; + } + + /* initialize */ + error = zinitix_write_u16(client, BT541_X_RESOLUTION, + bt541->prop.max_x); + if (error) + return error; + + error = zinitix_write_u16(client, BT541_Y_RESOLUTION, + bt541->prop.max_y); + if (error) + return error; + + error = zinitix_write_u16(client, BT541_SUPPORTED_FINGER_NUM, + MAX_SUPPORTED_FINGER_NUM); + if (error) + return error; + + error = zinitix_write_u16(client, BT541_INITIAL_TOUCH_MODE, + bt541->zinitix_mode); + if (error) + return error; + + error = zinitix_write_u16(client, BT541_TOUCH_MODE, + bt541->zinitix_mode); + if (error) + return error; + + error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, + BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE | + BIT_UP); + if (error) + return error; + + /* clear queue */ + for (i = 0; i < 10; i++) { + zinitix_write_cmd(client, BT541_CLEAR_INT_STATUS_CMD); + udelay(10); + } + + return 0; +} + +static int zinitix_init_regulators(struct bt541_ts_data *bt541) +{ + struct i2c_client *client = bt541->client; + int error; + + bt541->supplies[0].supply = "vdd"; + bt541->supplies[1].supply = "vddo"; + error = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(bt541->supplies), + bt541->supplies); + if (error < 0) { + dev_err(&client->dev, "Failed to get regulators: %d\n", error); + return error; + } + + return 0; +} + +static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541) +{ + int error; + struct i2c_client *client = bt541->client; + + error = zinitix_write_u16(client, 0xc000, 0x0001); + if (error) { + dev_err(&client->dev, + "Failed to send power sequence(vendor cmd enable)\n"); + return error; + } + udelay(10); + + error = zinitix_write_cmd(client, 0xc004); + if (error) { + dev_err(&client->dev, + "Failed to send power sequence (intn clear)\n"); + return error; + } + udelay(10); + + error = zinitix_write_u16(client, 0xc002, 0x0001); + if (error) { + dev_err(&client->dev, + "Failed to send power sequence (nvm init)\n"); + return error; + } + mdelay(2); + + error = zinitix_write_u16(client, 0xc001, 0x0001); + if (error) { + dev_err(&client->dev, + "Failed to send power sequence (program start)\n"); + return error; + } + msleep(FIRMWARE_ON_DELAY); + + return 0; +} + +static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot, + const struct point_coord *p) +{ + input_mt_slot(bt541->input_dev, slot); + input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true); + touchscreen_report_pos(bt541->input_dev, &bt541->prop, + le16_to_cpu(p->x), le16_to_cpu(p->y), true); + input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width); +} + +static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler) +{ + struct bt541_ts_data *bt541 = bt541_handler; + struct i2c_client *client = bt541->client; + struct touch_event touch_event; + int error; + int i; + + memset(&touch_event, 0, sizeof(struct touch_event)); + + error = zinitix_read_data(bt541->client, BT541_POINT_STATUS_REG, + &touch_event, sizeof(struct touch_event)); + if (error) { + dev_err(&client->dev, "Failed to read in touchpoint struct\n"); + goto out; + } + + for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++) + if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST) + zinitix_report_finger(bt541, i, + &touch_event.point_coord[i]); + + input_mt_sync_frame(bt541->input_dev); + input_sync(bt541->input_dev); + +out: + zinitix_write_cmd(bt541->client, BT541_CLEAR_INT_STATUS_CMD); + return IRQ_HANDLED; +} + +static int zinitix_start(struct bt541_ts_data *bt541) +{ + int error; + + error = regulator_bulk_enable(ARRAY_SIZE(bt541->supplies), + bt541->supplies); + if (error) { + dev_err(&bt541->client->dev, + "Failed to enable regulators: %d\n", error); + return error; + } + + msleep(CHIP_ON_DELAY); + + error = zinitix_send_power_on_sequence(bt541); + if (error) { + dev_err(&bt541->client->dev, + "Error while sending power-on sequence: %d\n", error); + return error; + } + + error = zinitix_init_touch(bt541); + if (error) { + dev_err(&bt541->client->dev, + "Error while configuring touch IC\n"); + return error; + } + + enable_irq(bt541->client->irq); + + return 0; +} + +static int zinitix_stop(struct bt541_ts_data *bt541) +{ + int error; + + disable_irq(bt541->client->irq); + + error = regulator_bulk_disable(ARRAY_SIZE(bt541->supplies), + bt541->supplies); + if (error) { + dev_err(&bt541->client->dev, + "Failed to disable regulators: %d\n", error); + return error; + } + + return 0; +} + +static int zinitix_input_open(struct input_dev *dev) +{ + struct bt541_ts_data *bt541 = input_get_drvdata(dev); + + return zinitix_start(bt541); +} + +static void zinitix_input_close(struct input_dev *dev) +{ + struct bt541_ts_data *bt541 = input_get_drvdata(dev); + + zinitix_stop(bt541); +} + +static int zinitix_init_input_dev(struct bt541_ts_data *bt541) +{ + struct input_dev *input_dev; + int error; + + input_dev = devm_input_allocate_device(&bt541->client->dev); + if (!input_dev) { + dev_err(&bt541->client->dev, + "Failed to allocate input device."); + return -ENOMEM; + } + + input_set_drvdata(input_dev, bt541); + bt541->input_dev = input_dev; + + input_dev->name = "Zinitix Capacitive TouchScreen"; + input_dev->phys = "input/ts"; + input_dev->id.bustype = BUS_I2C; + input_dev->open = zinitix_input_open; + input_dev->close = zinitix_input_close; + + input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + touchscreen_parse_properties(input_dev, true, &bt541->prop); + if (!bt541->prop.max_x || !bt541->prop.max_y) { + dev_err(&bt541->client->dev, + "Touchscreen-size-x and/or touchscreen-size-y not set in dts\n"); + return -EINVAL; + } + + error = input_mt_init_slots(input_dev, MAX_SUPPORTED_FINGER_NUM, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&bt541->client->dev, + "Failed to initialize MT slots: %d", error); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(&bt541->client->dev, + "Failed to register input device: %d", error); + return error; + } + + return 0; +} + +static int zinitix_ts_probe(struct i2c_client *client) +{ + struct bt541_ts_data *bt541; + int error; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "Failed to assert adapter's support for plain I2C.\n"); + return -ENXIO; + } + + bt541 = devm_kzalloc(&client->dev, sizeof(*bt541), GFP_KERNEL); + if (!bt541) + return -ENOMEM; + + bt541->client = client; + i2c_set_clientdata(client, bt541); + + error = zinitix_init_regulators(bt541); + if (error) { + dev_err(&client->dev, + "Failed to initialize regulators: %d\n", error); + return error; + } + + error = zinitix_init_input_dev(bt541); + if (error) { + dev_err(&client->dev, + "Failed to initialize input device: %d\n", error); + return error; + } + + error = device_property_read_u32(&client->dev, "zinitix,mode", + &bt541->zinitix_mode); + if (error < 0) { + /* fall back to mode 2 */ + bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE; + } + + if (bt541->zinitix_mode != 2) { + /* + * If there are devices that don't support mode 2, support + * for other modes (0, 1) will be needed. + */ + dev_err(&client->dev, + "Malformed zinitix,mode property, must be 2 (supplied: %d)\n", + bt541->zinitix_mode); + return -EINVAL; + } + + irq_set_status_flags(client->irq, IRQ_NOAUTOEN); + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, zinitix_ts_irq_handler, + IRQF_ONESHOT, client->name, bt541); + if (error) { + dev_err(&client->dev, "Failed to request IRQ: %d\n", error); + return error; + } + + return 0; +} + +static int __maybe_unused zinitix_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_data *bt541 = i2c_get_clientdata(client); + + mutex_lock(&bt541->input_dev->mutex); + + if (bt541->input_dev->users) + zinitix_stop(bt541); + + mutex_unlock(&bt541->input_dev->mutex); + + return 0; +} + +static int __maybe_unused zinitix_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct bt541_ts_data *bt541 = i2c_get_clientdata(client); + int ret = 0; + + mutex_lock(&bt541->input_dev->mutex); + + if (bt541->input_dev->users) + ret = zinitix_start(bt541); + + mutex_unlock(&bt541->input_dev->mutex); + + return ret; +} + +static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume); + +#ifdef CONFIG_OF +static const struct of_device_id zinitix_of_match[] = { + { .compatible = "zinitix,bt541" }, + { } +}; +MODULE_DEVICE_TABLE(of, zinitix_of_match); +#endif + +static struct i2c_driver zinitix_ts_driver = { + .probe_new = zinitix_ts_probe, + .driver = { + .name = "Zinitix-TS", + .pm = &zinitix_pm_ops, + .of_match_table = of_match_ptr(zinitix_of_match), + }, +}; +module_i2c_driver(zinitix_ts_driver); + +MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>"); +MODULE_DESCRIPTION("Zinitix touchscreen driver"); +MODULE_LICENSE("GPL v2"); |