diff options
Diffstat (limited to 'drivers/input')
27 files changed, 2659 insertions, 773 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 0d57e51b8ba1..e494295d1c7b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -282,7 +282,8 @@ static void evdev_pass_values(struct evdev_client *client, spin_unlock(&client->buffer_lock); if (wakeup) - wake_up_interruptible(&evdev->wait); + wake_up_interruptible_poll(&evdev->wait, + EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); } /* @@ -429,7 +430,7 @@ static void evdev_hangup(struct evdev *evdev) kill_fasync(&client->fasync, SIGIO, POLL_HUP); spin_unlock(&evdev->client_lock); - wake_up_interruptible(&evdev->wait); + wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); } static int evdev_release(struct inode *inode, struct file *file) @@ -945,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(&evdev->wait); + wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); return 0; } diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 940b744639c7..6f73f02059b5 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -45,6 +45,7 @@ config JOYSTICK_A3D config JOYSTICK_ADI tristate "Logitech ADI digital joysticks and gamepads" select GAMEPORT + depends on ADI!=m # avoid module name conflict help Say Y here if you have a Logitech controller using the ADI protocol over the PC gameport. diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 28de965a08d5..793ecbbda32c 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -701,7 +701,7 @@ config KEYBOARD_SPEAR Say Y here if you want to use the SPEAR keyboard. To compile this driver as a module, choose M here: the - module will be called spear-keboard. + module will be called spear-keyboard. config KEYBOARD_TC3589X tristate "TC3589X Keypad support" diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 7e3eae54c192..6ec28265771d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -24,6 +24,7 @@ #include <linux/libps2.h> #include <linux/mutex.h> #include <linux/dmi.h> +#include <linux/property.h> #define DRIVER_DESC "AT and PS/2 keyboard driver" @@ -63,6 +64,11 @@ static bool atkbd_terminal; module_param_named(terminal, atkbd_terminal, bool, 0); MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2"); +#define MAX_FUNCTION_ROW_KEYS 24 + +#define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) +#define KEYCODE(keymap) (keymap & 0xFFFF) + /* * Scancode to keycode tables. These are just the default setting, and * are loadable via a userland utility. @@ -230,6 +236,9 @@ struct atkbd { /* Serializes reconnect(), attr->set() and event work */ struct mutex mutex; + + u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS]; + int num_function_row_keys; }; /* @@ -283,6 +292,7 @@ static struct device_attribute atkbd_attr_##_name = \ __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); ATKBD_DEFINE_RO_ATTR(err_count); +ATKBD_DEFINE_RO_ATTR(function_row_physmap); static struct attribute *atkbd_attributes[] = { &atkbd_attr_extra.attr, @@ -292,11 +302,42 @@ static struct attribute *atkbd_attributes[] = { &atkbd_attr_softrepeat.attr, &atkbd_attr_softraw.attr, &atkbd_attr_err_count.attr, + &atkbd_attr_function_row_physmap.attr, NULL }; +static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf) +{ + ssize_t size = 0; + int i; + + if (!atkbd->num_function_row_keys) + return 0; + + for (i = 0; i < atkbd->num_function_row_keys; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ", + atkbd->function_row_physmap[i]); + size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); + return size; +} + +static umode_t atkbd_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int i) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct serio *serio = to_serio_port(dev); + struct atkbd *atkbd = serio_get_drvdata(serio); + + if (attr == &atkbd_attr_function_row_physmap.attr && + !atkbd->num_function_row_keys) + return 0; + + return attr->mode; +} + static struct attribute_group atkbd_attribute_group = { .attrs = atkbd_attributes, + .is_visible = atkbd_attr_is_visible, }; static const unsigned int xl_table[] = { @@ -994,6 +1035,39 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, return code; } +static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) +{ + struct device *dev = &atkbd->ps2dev.serio->dev; + int i, n; + u32 *ptr; + u16 scancode, keycode; + + /* Parse "linux,keymap" property */ + n = device_property_count_u32(dev, "linux,keymap"); + if (n <= 0 || n > ATKBD_KEYMAP_SIZE) + return -ENXIO; + + ptr = kcalloc(n, sizeof(u32), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) { + dev_err(dev, "problem parsing FW keymap property\n"); + kfree(ptr); + return -EINVAL; + } + + memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); + for (i = 0; i < n; i++) { + scancode = SCANCODE(ptr[i]); + keycode = KEYCODE(ptr[i]); + atkbd->keycode[scancode] = keycode; + } + + kfree(ptr); + return 0; +} + /* * atkbd_set_keycode_table() initializes keyboard's keycode table * according to the selected scancode set @@ -1001,13 +1075,16 @@ static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, static void atkbd_set_keycode_table(struct atkbd *atkbd) { + struct device *dev = &atkbd->ps2dev.serio->dev; unsigned int scancode; int i, j; memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); - if (atkbd->translated) { + if (!atkbd_get_keymap_from_fwnode(atkbd)) { + dev_dbg(dev, "Using FW keymap\n"); + } else if (atkbd->translated) { for (i = 0; i < 128; i++) { scancode = atkbd_unxlate_table[i]; atkbd->keycode[i] = atkbd_set2_keycode[scancode]; @@ -1121,6 +1198,22 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) } } +static void atkbd_parse_fwnode_data(struct serio *serio) +{ + struct atkbd *atkbd = serio_get_drvdata(serio); + struct device *dev = &serio->dev; + int n; + + /* Parse "function-row-physmap" property */ + n = device_property_count_u32(dev, "function-row-physmap"); + if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS && + !device_property_read_u32_array(dev, "function-row-physmap", + atkbd->function_row_physmap, n)) { + atkbd->num_function_row_keys = n; + dev_dbg(dev, "FW reported %d function-row key locations\n", n); + } +} + /* * atkbd_connect() is called when the serio module finds an interface * that isn't handled yet by an appropriate device driver. We check if @@ -1184,6 +1277,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) atkbd->id = 0xab00; } + atkbd_parse_fwnode_data(serio); + atkbd_set_keycode_table(atkbd); atkbd_set_device_attrs(atkbd); diff --git a/drivers/input/keyboard/imx_sc_key.c b/drivers/input/keyboard/imx_sc_key.c index 9f809aeb785c..d18839f1f4f6 100644 --- a/drivers/input/keyboard/imx_sc_key.c +++ b/drivers/input/keyboard/imx_sc_key.c @@ -99,6 +99,15 @@ static void imx_sc_check_for_events(struct work_struct *work) msecs_to_jiffies(REPEAT_INTERVAL)); } +static void imx_sc_key_action(void *data) +{ + struct imx_key_drv_data *priv = data; + + imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON, false); + imx_scu_irq_unregister_notifier(&priv->key_notifier); + cancel_delayed_work_sync(&priv->check_work); +} + static int imx_sc_key_probe(struct platform_device *pdev) { struct imx_key_drv_data *priv; @@ -149,27 +158,16 @@ static int imx_sc_key_probe(struct platform_device *pdev) return error; } + error = devm_add_action_or_reset(&pdev->dev, imx_sc_key_action, &priv); + if (error) + return error; + priv->key_notifier.notifier_call = imx_sc_key_notify; error = imx_scu_irq_register_notifier(&priv->key_notifier); - if (error) { - imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON, - false); + if (error) dev_err(&pdev->dev, "failed to register scu notifier\n"); - return error; - } - - return 0; -} - -static int imx_sc_key_remove(struct platform_device *pdev) -{ - struct imx_key_drv_data *priv = platform_get_drvdata(pdev); - - imx_scu_irq_group_enable(SC_IRQ_GROUP_WAKE, SC_IRQ_BUTTON, false); - imx_scu_irq_unregister_notifier(&priv->key_notifier); - cancel_delayed_work_sync(&priv->check_work); - return 0; + return error; } static const struct of_device_id imx_sc_key_ids[] = { @@ -184,7 +182,6 @@ static struct platform_driver imx_sc_key_driver = { .of_match_table = imx_sc_key_ids, }, .probe = imx_sc_key_probe, - .remove = imx_sc_key_remove, }; module_platform_driver(imx_sc_key_driver); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 21758767ccf0..9b0f9665dcb0 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -374,5 +374,5 @@ static void __exit tca6416_keypad_exit(void) module_exit(tca6416_keypad_exit); MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>"); -MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander"); +MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7e2e658d551c..362e8a01980c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -117,16 +117,6 @@ config INPUT_E3X0_BUTTON To compile this driver as a module, choose M here: the module will be called e3x0_button. -config INPUT_MSM_VIBRATOR - tristate "Qualcomm MSM vibrator driver" - select INPUT_FF_MEMLESS - help - Support for the vibrator that is found on various Qualcomm MSM - SOCs. - - To compile this driver as a module, choose M here: the module - will be called msm_vibrator. - config INPUT_PCSPKR tristate "PC Speaker support" depends on PCSPKR_PLATFORM @@ -265,17 +255,6 @@ config INPUT_APANEL To compile this driver as a module, choose M here: the module will be called apanel. -config INPUT_GP2A - tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip - hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called gp2ap002a00f. - config INPUT_GPIO_BEEPER tristate "Generic GPIO Beeper support" depends on GPIOLIB || COMPILE_TEST @@ -739,6 +718,17 @@ config INPUT_IMS_PCU To compile this driver as a module, choose M here: the module will be called ims_pcu. +config INPUT_IQS269A + tristate "Azoteq IQS269A capacitive touch controller" + depends on I2C + select REGMAP_I2C + help + Say Y to enable support for the Azoteq IQS269A capacitive + touch controller. + + To compile this driver as a module, choose M here: the + module will be called iqs269a. + config INPUT_CMA3000 tristate "VTI CMA3000 Tri-axis accelerometer" help diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 8fd187f314bd..a48e5f2d859d 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -33,13 +33,13 @@ obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o -obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o +obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o @@ -50,7 +50,6 @@ obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o obj-$(CONFIG_INPUT_MMA8450) += mma8450.o -obj-$(CONFIG_INPUT_MSM_VIBRATOR) += msm-vibrator.o obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c deleted file mode 100644 index 90abda8eea67..000000000000 --- a/drivers/input/misc/gp2ap002a00f.c +++ /dev/null @@ -1,281 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2011 Sony Ericsson Mobile Communications Inc. - * - * Author: Courtney Cavin <courtney.cavin@sonyericsson.com> - * Prepared for up-stream by: Oskar Andero <oskar.andero@sonyericsson.com> - */ - -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/slab.h> -#include <linux/input.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/gpio.h> -#include <linux/delay.h> -#include <linux/input/gp2ap002a00f.h> - -struct gp2a_data { - struct input_dev *input; - const struct gp2a_platform_data *pdata; - struct i2c_client *i2c_client; -}; - -enum gp2a_addr { - GP2A_ADDR_PROX = 0x0, - GP2A_ADDR_GAIN = 0x1, - GP2A_ADDR_HYS = 0x2, - GP2A_ADDR_CYCLE = 0x3, - GP2A_ADDR_OPMOD = 0x4, - GP2A_ADDR_CON = 0x6 -}; - -enum gp2a_controls { - /* Software Shutdown control: 0 = shutdown, 1 = normal operation */ - GP2A_CTRL_SSD = 0x01 -}; - -static int gp2a_report(struct gp2a_data *dt) -{ - int vo = gpio_get_value(dt->pdata->vout_gpio); - - input_report_switch(dt->input, SW_FRONT_PROXIMITY, !vo); - input_sync(dt->input); - - return 0; -} - -static irqreturn_t gp2a_irq(int irq, void *handle) -{ - struct gp2a_data *dt = handle; - - gp2a_report(dt); - - return IRQ_HANDLED; -} - -static int gp2a_enable(struct gp2a_data *dt) -{ - return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD, - GP2A_CTRL_SSD); -} - -static int gp2a_disable(struct gp2a_data *dt) -{ - return i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_OPMOD, - 0x00); -} - -static int gp2a_device_open(struct input_dev *dev) -{ - struct gp2a_data *dt = input_get_drvdata(dev); - int error; - - error = gp2a_enable(dt); - if (error < 0) { - dev_err(&dt->i2c_client->dev, - "unable to activate, err %d\n", error); - return error; - } - - gp2a_report(dt); - - return 0; -} - -static void gp2a_device_close(struct input_dev *dev) -{ - struct gp2a_data *dt = input_get_drvdata(dev); - int error; - - error = gp2a_disable(dt); - if (error < 0) - dev_err(&dt->i2c_client->dev, - "unable to deactivate, err %d\n", error); -} - -static int gp2a_initialize(struct gp2a_data *dt) -{ - int error; - - error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_GAIN, - 0x08); - if (error < 0) - return error; - - error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_HYS, - 0xc2); - if (error < 0) - return error; - - error = i2c_smbus_write_byte_data(dt->i2c_client, GP2A_ADDR_CYCLE, - 0x04); - if (error < 0) - return error; - - error = gp2a_disable(dt); - - return error; -} - -static int gp2a_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - const struct gp2a_platform_data *pdata = dev_get_platdata(&client->dev); - struct gp2a_data *dt; - int error; - - if (!pdata) - return -EINVAL; - - if (pdata->hw_setup) { - error = pdata->hw_setup(client); - if (error < 0) - return error; - } - - error = gpio_request_one(pdata->vout_gpio, GPIOF_IN, GP2A_I2C_NAME); - if (error) - goto err_hw_shutdown; - - dt = kzalloc(sizeof(struct gp2a_data), GFP_KERNEL); - if (!dt) { - error = -ENOMEM; - goto err_free_gpio; - } - - dt->pdata = pdata; - dt->i2c_client = client; - - error = gp2a_initialize(dt); - if (error < 0) - goto err_free_mem; - - dt->input = input_allocate_device(); - if (!dt->input) { - error = -ENOMEM; - goto err_free_mem; - } - - input_set_drvdata(dt->input, dt); - - dt->input->open = gp2a_device_open; - dt->input->close = gp2a_device_close; - dt->input->name = GP2A_I2C_NAME; - dt->input->id.bustype = BUS_I2C; - dt->input->dev.parent = &client->dev; - - input_set_capability(dt->input, EV_SW, SW_FRONT_PROXIMITY); - - error = request_threaded_irq(client->irq, NULL, gp2a_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | - IRQF_ONESHOT, - GP2A_I2C_NAME, dt); - if (error) { - dev_err(&client->dev, "irq request failed\n"); - goto err_free_input_dev; - } - - error = input_register_device(dt->input); - if (error) { - dev_err(&client->dev, "device registration failed\n"); - goto err_free_irq; - } - - device_init_wakeup(&client->dev, pdata->wakeup); - i2c_set_clientdata(client, dt); - - return 0; - -err_free_irq: - free_irq(client->irq, dt); -err_free_input_dev: - input_free_device(dt->input); -err_free_mem: - kfree(dt); -err_free_gpio: - gpio_free(pdata->vout_gpio); -err_hw_shutdown: - if (pdata->hw_shutdown) - pdata->hw_shutdown(client); - return error; -} - -static int gp2a_remove(struct i2c_client *client) -{ - struct gp2a_data *dt = i2c_get_clientdata(client); - const struct gp2a_platform_data *pdata = dt->pdata; - - free_irq(client->irq, dt); - - input_unregister_device(dt->input); - kfree(dt); - - gpio_free(pdata->vout_gpio); - - if (pdata->hw_shutdown) - pdata->hw_shutdown(client); - - return 0; -} - -static int __maybe_unused gp2a_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gp2a_data *dt = i2c_get_clientdata(client); - int retval = 0; - - if (device_may_wakeup(&client->dev)) { - enable_irq_wake(client->irq); - } else { - mutex_lock(&dt->input->mutex); - if (dt->input->users) - retval = gp2a_disable(dt); - mutex_unlock(&dt->input->mutex); - } - - return retval; -} - -static int __maybe_unused gp2a_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct gp2a_data *dt = i2c_get_clientdata(client); - int retval = 0; - - if (device_may_wakeup(&client->dev)) { - disable_irq_wake(client->irq); - } else { - mutex_lock(&dt->input->mutex); - if (dt->input->users) - retval = gp2a_enable(dt); - mutex_unlock(&dt->input->mutex); - } - - return retval; -} - -static SIMPLE_DEV_PM_OPS(gp2a_pm, gp2a_suspend, gp2a_resume); - -static const struct i2c_device_id gp2a_i2c_id[] = { - { GP2A_I2C_NAME, 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, gp2a_i2c_id); - -static struct i2c_driver gp2a_i2c_driver = { - .driver = { - .name = GP2A_I2C_NAME, - .pm = &gp2a_pm, - }, - .probe = gp2a_probe, - .remove = gp2a_remove, - .id_table = gp2a_i2c_id, -}; - -module_i2c_driver(gp2a_i2c_driver); - -MODULE_AUTHOR("Courtney Cavin <courtney.cavin@sonyericsson.com>"); -MODULE_DESCRIPTION("Sharp GP2AP002A00F I2C Proximity/Opto sensor driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c new file mode 100644 index 000000000000..6699eb160a0f --- /dev/null +++ b/drivers/input/misc/iqs269a.c @@ -0,0 +1,1833 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Azoteq IQS269A Capacitive Touch Controller + * + * Copyright (C) 2020 Jeff LaBundy <jeff@labundy.com> + * + * This driver registers up to 3 input devices: one representing capacitive or + * inductive keys as well as Hall-effect switches, and one for each of the two + * axial sliders presented by the device. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define IQS269_VER_INFO 0x00 +#define IQS269_VER_INFO_PROD_NUM 0x4F + +#define IQS269_SYS_FLAGS 0x02 +#define IQS269_SYS_FLAGS_SHOW_RESET BIT(15) +#define IQS269_SYS_FLAGS_PWR_MODE_MASK GENMASK(12, 11) +#define IQS269_SYS_FLAGS_PWR_MODE_SHIFT 11 +#define IQS269_SYS_FLAGS_IN_ATI BIT(10) + +#define IQS269_CHx_COUNTS 0x08 + +#define IQS269_SLIDER_X 0x30 + +#define IQS269_CAL_DATA_A 0x35 +#define IQS269_CAL_DATA_A_HALL_BIN_L_MASK GENMASK(15, 12) +#define IQS269_CAL_DATA_A_HALL_BIN_L_SHIFT 12 +#define IQS269_CAL_DATA_A_HALL_BIN_R_MASK GENMASK(11, 8) +#define IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT 8 + +#define IQS269_SYS_SETTINGS 0x80 +#define IQS269_SYS_SETTINGS_CLK_DIV BIT(15) +#define IQS269_SYS_SETTINGS_ULP_AUTO BIT(14) +#define IQS269_SYS_SETTINGS_DIS_AUTO BIT(13) +#define IQS269_SYS_SETTINGS_PWR_MODE_MASK GENMASK(12, 11) +#define IQS269_SYS_SETTINGS_PWR_MODE_SHIFT 11 +#define IQS269_SYS_SETTINGS_PWR_MODE_MAX 3 +#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8) +#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8 +#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7 +#define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6) +#define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5) +#define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4) +#define IQS269_SYS_SETTINGS_REDO_ATI BIT(2) +#define IQS269_SYS_SETTINGS_ACK_RESET BIT(0) + +#define IQS269_FILT_STR_LP_LTA_MASK GENMASK(7, 6) +#define IQS269_FILT_STR_LP_LTA_SHIFT 6 +#define IQS269_FILT_STR_LP_CNT_MASK GENMASK(5, 4) +#define IQS269_FILT_STR_LP_CNT_SHIFT 4 +#define IQS269_FILT_STR_NP_LTA_MASK GENMASK(3, 2) +#define IQS269_FILT_STR_NP_LTA_SHIFT 2 +#define IQS269_FILT_STR_NP_CNT_MASK GENMASK(1, 0) +#define IQS269_FILT_STR_MAX 3 + +#define IQS269_EVENT_MASK_SYS BIT(6) +#define IQS269_EVENT_MASK_DEEP BIT(2) +#define IQS269_EVENT_MASK_TOUCH BIT(1) +#define IQS269_EVENT_MASK_PROX BIT(0) + +#define IQS269_RATE_NP_MS_MAX 255 +#define IQS269_RATE_LP_MS_MAX 255 +#define IQS269_RATE_ULP_MS_MAX 4080 +#define IQS269_TIMEOUT_PWR_MS_MAX 130560 +#define IQS269_TIMEOUT_LTA_MS_MAX 130560 + +#define IQS269_MISC_A_ATI_BAND_DISABLE BIT(15) +#define IQS269_MISC_A_ATI_LP_ONLY BIT(14) +#define IQS269_MISC_A_ATI_BAND_TIGHTEN BIT(13) +#define IQS269_MISC_A_FILT_DISABLE BIT(12) +#define IQS269_MISC_A_GPIO3_SELECT_MASK GENMASK(10, 8) +#define IQS269_MISC_A_GPIO3_SELECT_SHIFT 8 +#define IQS269_MISC_A_DUAL_DIR BIT(6) +#define IQS269_MISC_A_TX_FREQ_MASK GENMASK(5, 4) +#define IQS269_MISC_A_TX_FREQ_SHIFT 4 +#define IQS269_MISC_A_TX_FREQ_MAX 3 +#define IQS269_MISC_A_GLOBAL_CAP_SIZE BIT(0) + +#define IQS269_MISC_B_RESEED_UI_SEL_MASK GENMASK(7, 6) +#define IQS269_MISC_B_RESEED_UI_SEL_SHIFT 6 +#define IQS269_MISC_B_RESEED_UI_SEL_MAX 3 +#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4) +#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0) + +#define IQS269_CHx_SETTINGS 0x8C + +#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15) +#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13) +#define IQS269_CHx_ENG_A_LOCAL_CAP_SIZE BIT(12) +#define IQS269_CHx_ENG_A_ATI_MODE_MASK GENMASK(9, 8) +#define IQS269_CHx_ENG_A_ATI_MODE_SHIFT 8 +#define IQS269_CHx_ENG_A_ATI_MODE_MAX 3 +#define IQS269_CHx_ENG_A_INV_LOGIC BIT(7) +#define IQS269_CHx_ENG_A_PROJ_BIAS_MASK GENMASK(6, 5) +#define IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT 5 +#define IQS269_CHx_ENG_A_PROJ_BIAS_MAX 3 +#define IQS269_CHx_ENG_A_SENSE_MODE_MASK GENMASK(3, 0) +#define IQS269_CHx_ENG_A_SENSE_MODE_MAX 15 + +#define IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE BIT(13) +#define IQS269_CHx_ENG_B_SENSE_FREQ_MASK GENMASK(10, 9) +#define IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT 9 +#define IQS269_CHx_ENG_B_SENSE_FREQ_MAX 3 +#define IQS269_CHx_ENG_B_STATIC_ENABLE BIT(8) +#define IQS269_CHx_ENG_B_ATI_BASE_MASK GENMASK(7, 6) +#define IQS269_CHx_ENG_B_ATI_BASE_75 0x00 +#define IQS269_CHx_ENG_B_ATI_BASE_100 0x40 +#define IQS269_CHx_ENG_B_ATI_BASE_150 0x80 +#define IQS269_CHx_ENG_B_ATI_BASE_200 0xC0 +#define IQS269_CHx_ENG_B_ATI_TARGET_MASK GENMASK(5, 0) +#define IQS269_CHx_ENG_B_ATI_TARGET_MAX 2016 + +#define IQS269_CHx_WEIGHT_MAX 255 +#define IQS269_CHx_THRESH_MAX 255 +#define IQS269_CHx_HYST_DEEP_MASK GENMASK(7, 4) +#define IQS269_CHx_HYST_DEEP_SHIFT 4 +#define IQS269_CHx_HYST_TOUCH_MASK GENMASK(3, 0) +#define IQS269_CHx_HYST_MAX 15 + +#define IQS269_CHx_HALL_INACTIVE 6 +#define IQS269_CHx_HALL_ACTIVE 7 + +#define IQS269_HALL_PAD_R BIT(0) +#define IQS269_HALL_PAD_L BIT(1) +#define IQS269_HALL_PAD_INV BIT(6) + +#define IQS269_HALL_UI 0xF5 +#define IQS269_HALL_UI_ENABLE BIT(15) + +#define IQS269_MAX_REG 0xFF + +#define IQS269_NUM_CH 8 +#define IQS269_NUM_SL 2 + +#define IQS269_ATI_POLL_SLEEP_US (iqs269->delay_mult * 10000) +#define IQS269_ATI_POLL_TIMEOUT_US (iqs269->delay_mult * 500000) +#define IQS269_ATI_STABLE_DELAY_MS (iqs269->delay_mult * 150) + +#define IQS269_PWR_MODE_POLL_SLEEP_US IQS269_ATI_POLL_SLEEP_US +#define IQS269_PWR_MODE_POLL_TIMEOUT_US IQS269_ATI_POLL_TIMEOUT_US + +#define iqs269_irq_wait() usleep_range(100, 150) + +enum iqs269_local_cap_size { + IQS269_LOCAL_CAP_SIZE_0, + IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY, + IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5, +}; + +enum iqs269_st_offs { + IQS269_ST_OFFS_PROX, + IQS269_ST_OFFS_DIR, + IQS269_ST_OFFS_TOUCH, + IQS269_ST_OFFS_DEEP, +}; + +enum iqs269_th_offs { + IQS269_TH_OFFS_PROX, + IQS269_TH_OFFS_TOUCH, + IQS269_TH_OFFS_DEEP, +}; + +enum iqs269_event_id { + IQS269_EVENT_PROX_DN, + IQS269_EVENT_PROX_UP, + IQS269_EVENT_TOUCH_DN, + IQS269_EVENT_TOUCH_UP, + IQS269_EVENT_DEEP_DN, + IQS269_EVENT_DEEP_UP, +}; + +struct iqs269_switch_desc { + unsigned int code; + bool enabled; +}; + +struct iqs269_event_desc { + const char *name; + enum iqs269_st_offs st_offs; + enum iqs269_th_offs th_offs; + bool dir_up; + u8 mask; +}; + +static const struct iqs269_event_desc iqs269_events[] = { + [IQS269_EVENT_PROX_DN] = { + .name = "event-prox", + .st_offs = IQS269_ST_OFFS_PROX, + .th_offs = IQS269_TH_OFFS_PROX, |