diff options
Diffstat (limited to 'drivers/input')
295 files changed, 7480 insertions, 6544 deletions
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 930b64d2115e..2cd6e1c9a778 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_INPUT) += input-core.o input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o -input-core-y += touchscreen.o +input-core-y += touchscreen.o touch-overlay.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o diff --git a/drivers/input/apm-power.c b/drivers/input/apm-power.c index 70a9e1dfba33..028fcaf4c142 100644 --- a/drivers/input/apm-power.c +++ b/drivers/input/apm-power.c @@ -52,7 +52,7 @@ static int apmpower_connect(struct input_handler *handler, struct input_handle *handle; int error; - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + handle = kzalloc_obj(struct input_handle); if (!handle) return -ENOMEM; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index b5cbb57ee5f6..c7325226cb86 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -465,7 +465,7 @@ static int evdev_open(struct inode *inode, struct file *file) struct evdev_client *client; int error; - client = kvzalloc(struct_size(client, buffer, bufsize), GFP_KERNEL); + client = kvzalloc_flex(*client, buffer, bufsize); if (!client) return -ENOMEM; @@ -1346,7 +1346,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, return error; } - evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); + evdev = kzalloc_obj(struct evdev); if (!evdev) { error = -ENOMEM; goto err_free_minor; @@ -1408,8 +1408,12 @@ static void evdev_disconnect(struct input_handle *handle) } static const struct input_device_id evdev_ids[] = { - { .driver_info = 1 }, /* Matches all devices */ - { }, /* Terminating zero entry */ + { + /* Matches all devices */ + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_SYN) }, + }, + { } /* Terminating zero entry */ }; MODULE_DEVICE_TABLE(input, evdev_ids); diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index b527308cb52e..0e5d1d1ceb46 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -8,9 +8,9 @@ /* #define DEBUG */ +#include <linux/export.h> #include <linux/input.h> #include <linux/limits.h> -#include <linux/module.h> #include <linux/mutex.h> #include <linux/overflow.h> #include <linux/sched.h> @@ -303,12 +303,11 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) } struct ff_device *ff __free(kfree) = - kzalloc(struct_size(ff, effect_owners, max_effects), - GFP_KERNEL); + kzalloc_flex(*ff, effect_owners, max_effects); if (!ff) return -ENOMEM; - ff->effects = kcalloc(max_effects, sizeof(*ff->effects), GFP_KERNEL); + ff->effects = kzalloc_objs(*ff->effects, max_effects); if (!ff->effects) return -ENOMEM; diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c index e9120ba6bae0..937370d04928 100644 --- a/drivers/input/ff-memless.c +++ b/drivers/input/ff-memless.c @@ -10,6 +10,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/export.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/module.h> @@ -136,7 +137,7 @@ static void ml_schedule_timer(struct ml_device *ml) if (!events) { pr_debug("no actions\n"); - del_timer(&ml->timer); + timer_delete(&ml->timer); } else { pr_debug("timer set\n"); mod_timer(&ml->timer, earliest); @@ -399,7 +400,7 @@ static void ml_play_effects(struct ml_device *ml) static void ml_effect_timer(struct timer_list *t) { - struct ml_device *ml = from_timer(ml, t, timer); + struct ml_device *ml = timer_container_of(ml, t, timer); struct input_dev *dev = ml->dev; pr_debug("timer: updating effects\n"); @@ -489,7 +490,7 @@ static void ml_ff_destroy(struct ff_device *ff) * do not actually stop the timer, and therefore we should * do it here. */ - del_timer_sync(&ml->timer); + timer_delete_sync(&ml->timer); kfree(ml->private); } @@ -507,7 +508,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data, int error; int i; - struct ml_device *ml __free(kfree) = kzalloc(sizeof(*ml), GFP_KERNEL); + struct ml_device *ml __free(kfree) = kzalloc_obj(*ml); if (!ml) return -ENOMEM; diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 4f4583048f24..ee97621df59d 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -43,7 +43,7 @@ static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct gameport *port; int error; - emu = kzalloc(sizeof(*emu), GFP_KERNEL); + emu = kzalloc_obj(*emu); port = gameport_allocate_port(); if (!emu || !port) { printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n"); diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 7ae5009385cc..1e8c6c044844 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -68,7 +68,7 @@ static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id) struct gameport *port; int error; - gp = kzalloc(sizeof(*gp), GFP_KERNEL); + gp = kzalloc_obj(*gp); port = gameport_allocate_port(); if (!gp || !port) { printk(KERN_ERR "fm801-gp: Memory allocation failed\n"); @@ -125,8 +125,8 @@ static void fm801_gp_remove(struct pci_dev *pci) } static const struct pci_device_id fm801_gp_id_table[] = { - { PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0 } + { PCI_VDEVICE(FORTEMEDIA, PCI_DEVICE_ID_FM801_GP) }, + { } }; MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 10cc95867415..9707b155bc94 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/export.h> #include <linux/stddef.h> #include <linux/module.h> #include <linux/io.h> @@ -191,7 +192,7 @@ void gameport_stop_polling(struct gameport *gameport) spin_lock(&gameport->timer_lock); if (!--gameport->poll_cnt) - del_timer(&gameport->poll_timer); + timer_delete(&gameport->poll_timer); spin_unlock(&gameport->timer_lock); } @@ -199,7 +200,8 @@ EXPORT_SYMBOL(gameport_stop_polling); static void gameport_run_poll_handler(struct timer_list *t) { - struct gameport *gameport = from_timer(gameport, t, poll_timer); + struct gameport *gameport = timer_container_of(gameport, t, + poll_timer); gameport->poll_handler(gameport); if (gameport->poll_cnt) @@ -372,7 +374,7 @@ static int gameport_queue_event(void *object, struct module *owner, } } - event = kmalloc(sizeof(*event), GFP_ATOMIC); + event = kmalloc_obj(*event, GFP_ATOMIC); if (!event) { pr_err("Not enough memory to queue event %d\n", event_type); retval = -ENOMEM; @@ -847,7 +849,7 @@ EXPORT_SYMBOL(gameport_open); void gameport_close(struct gameport *gameport) { - del_timer_sync(&gameport->poll_timer); + timer_delete_sync(&gameport->poll_timer); gameport->poll_handler = NULL; gameport->poll_interval = 0; gameport_set_drv(gameport, NULL); diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c index 880e714b49bc..fdece6ec1df3 100644 --- a/drivers/input/gameport/ns558.c +++ b/drivers/input/gameport/ns558.c @@ -120,7 +120,7 @@ static int ns558_isa_probe(int io) return -EBUSY; } - ns558 = kzalloc(sizeof(*ns558), GFP_KERNEL); + ns558 = kzalloc_obj(*ns558); port = gameport_allocate_port(); if (!ns558 || !port) { printk(KERN_ERR "ns558: Memory allocation failed.\n"); @@ -192,7 +192,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did) if (!request_region(ioport, iolen, "ns558-pnp")) return -EBUSY; - ns558 = kzalloc(sizeof(*ns558), GFP_KERNEL); + ns558 = kzalloc_obj(*ns558); port = gameport_allocate_port(); if (!ns558 || !port) { printk(KERN_ERR "ns558: Memory allocation failed\n"); diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index 2ccd3eedbd67..a5043193ead8 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -6,6 +6,7 @@ */ #include <linux/export.h> +#include <linux/sprintf.h> #include <linux/uaccess.h> #include "input-compat.h" @@ -94,6 +95,28 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, return 0; } +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty) +{ + int len = 0; + + if (in_compat_syscall()) { + u32 dword = bits >> 32; + if (dword || !skip_empty) + len += snprintf(buf, buf_size, "%x ", dword); + + dword = bits & 0xffffffffUL; + if (dword || !skip_empty || len) + len += snprintf(buf + len, max(buf_size - len, 0), + "%x", dword); + } else { + if (bits || !skip_empty) + len += snprintf(buf, buf_size, "%lx", bits); + } + + return len; +} + #else int input_event_from_user(const char __user *buffer, @@ -126,6 +149,13 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, return 0; } +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty) +{ + return bits || !skip_empty ? + snprintf(buf, buf_size, "%lx", bits) : 0; +} + #endif /* CONFIG_COMPAT */ EXPORT_SYMBOL_GPL(input_event_from_user); diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h index 3b7bb12b023b..99c87ceb923d 100644 --- a/drivers/input/input-compat.h +++ b/drivers/input/input-compat.h @@ -75,4 +75,7 @@ int input_event_to_user(char __user *buffer, int input_ff_effect_from_user(const char __user *buffer, size_t size, struct ff_effect *effect); +int input_bits_to_string(char *buf, int buf_size, unsigned long bits, + bool skip_empty); + #endif /* _INPUT_COMPAT_H */ diff --git a/drivers/input/input-leds.c b/drivers/input/input-leds.c index 6bbf3806ea37..b08d1d08d0b4 100644 --- a/drivers/input/input-leds.c +++ b/drivers/input/input-leds.c @@ -101,7 +101,7 @@ static int input_leds_connect(struct input_handler *handler, if (!num_leds) return -ENXIO; - leds = kzalloc(struct_size(leds, leds, num_leds), GFP_KERNEL); + leds = kzalloc_flex(*leds, leds, num_leds); if (!leds) return -ENOMEM; diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index 337006dd9dcf..c06e98fbd77c 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -50,7 +50,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, return -EINVAL; struct input_mt *mt __free(kfree) = - kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL); + kzalloc_flex(*mt, slots, num_slots); if (!mt) return -ENOMEM; @@ -84,7 +84,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); if (flags & INPUT_MT_TRACK) { unsigned int n2 = num_slots * num_slots; - mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL); + mt->red = kzalloc_objs(*mt->red, n2); if (!mt->red) return -ENOMEM; } @@ -198,6 +198,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) struct input_mt *mt = dev->mt; struct input_mt_slot *oldest; int oldid, count, i; + int p, reported_p = 0; if (!mt) return; @@ -216,6 +217,13 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) oldest = ps; oldid = id; } + if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { + p = input_mt_get_value(ps, ABS_MT_PRESSURE); + if (mt->flags & INPUT_MT_TOTAL_FORCE) + reported_p += p; + else if (oldid == id) + reported_p = p; + } count++; } @@ -245,10 +253,8 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) input_event(dev, EV_ABS, ABS_X, x); input_event(dev, EV_ABS, ABS_Y, y); - if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { - int p = input_mt_get_value(oldest, ABS_MT_PRESSURE); - input_event(dev, EV_ABS, ABS_PRESSURE, p); - } + if (test_bit(ABS_MT_PRESSURE, dev->absbit)) + input_event(dev, EV_ABS, ABS_PRESSURE, reported_p); } else { if (test_bit(ABS_MT_PRESSURE, dev->absbit)) input_event(dev, EV_ABS, ABS_PRESSURE, 0); diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c index 9c57713a6151..54dc07fcae0b 100644 --- a/drivers/input/input-poller.c +++ b/drivers/input/input-poller.c @@ -4,6 +4,7 @@ */ #include <linux/device.h> +#include <linux/export.h> #include <linux/input.h> #include <linux/jiffies.h> #include <linux/mutex.h> @@ -70,7 +71,7 @@ int input_setup_polling(struct input_dev *dev, { struct input_dev_poller *poller; - poller = kzalloc(sizeof(*poller), GFP_KERNEL); + poller = kzalloc_obj(*poller); if (!poller) { /* * We want to show message even though kzalloc() may have diff --git a/drivers/input/input.c b/drivers/input/input.c index c9e3ac64bcd0..39d9d2b1e3ca 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_BASENAME ": " fmt +#include <linux/export.h> #include <linux/init.h> #include <linux/types.h> #include <linux/idr.h> @@ -96,7 +97,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code) static void input_stop_autorepeat(struct input_dev *dev) { - del_timer(&dev->timer); + timer_delete(&dev->timer); } /* @@ -438,7 +439,7 @@ void input_alloc_absinfo(struct input_dev *dev) if (dev->absinfo) return; - dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo), GFP_KERNEL); + dev->absinfo = kzalloc_objs(*dev->absinfo, ABS_CNT); if (!dev->absinfo) { dev_err(dev->dev.parent ?: &dev->dev, "%s: unable to allocate memory\n", __func__); @@ -799,14 +800,30 @@ static int input_default_getkeycode(struct input_dev *dev, return 0; } -static int input_default_setkeycode(struct input_dev *dev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode) +/** + * input_default_setkeycode - default setkeycode method + * @dev: input device which keymap is being updated. + * @ke: new keymap entry. + * @old_keycode: pointer to the location where old keycode should be stored. + * + * This function is the default implementation of &input_dev.setkeycode() + * method. It is typically used when a driver does not provide its own + * implementation, but it is also exported so drivers can extend it. + * + * The function must be called with &input_dev.event_lock held. + * + * Return: 0 on success, or a negative error code on failure. + */ +int input_default_setkeycode(struct input_dev *dev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) { unsigned int index; int error; int i; + lockdep_assert_held(&dev->event_lock); + if (!dev->keycodesize) return -EINVAL; @@ -860,6 +877,7 @@ static int input_default_setkeycode(struct input_dev *dev, __set_bit(ke->keycode, dev->keybit); return 0; } +EXPORT_SYMBOL(input_default_setkeycode); /** * input_get_keycode - retrieve keycode currently mapped to a given scancode @@ -971,7 +989,7 @@ static const struct input_device_id *input_match_device(struct input_handler *ha { const struct input_device_id *id; - for (id = handler->id_table; id->flags || id->driver_info; id++) { + for (id = handler->id_table; id->flags; id++) { if (input_match_device_id(dev, id) && (!handler->match || handler->match(handler, dev))) { return id; @@ -998,41 +1016,6 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han return error; } -#ifdef CONFIG_COMPAT - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - int len = 0; - - if (in_compat_syscall()) { - u32 dword = bits >> 32; - if (dword || !skip_empty) - len += snprintf(buf, buf_size, "%x ", dword); - - dword = bits & 0xffffffffUL; - if (dword || !skip_empty || len) - len += snprintf(buf + len, max(buf_size - len, 0), - "%x", dword); - } else { - if (bits || !skip_empty) - len += snprintf(buf, buf_size, "%lx", bits); - } - - return len; -} - -#else /* !CONFIG_COMPAT */ - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - return bits || !skip_empty ? - snprintf(buf, buf_size, "%lx", bits) : 0; -} - -#endif - #ifdef CONFIG_PROC_FS static struct proc_dir_entry *proc_bus_input_dir; @@ -1921,7 +1904,7 @@ struct input_dev *input_allocate_device(void) static atomic_t input_no = ATOMIC_INIT(-1); struct input_dev *dev; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc_obj(*dev); if (!dev) return NULL; @@ -1931,7 +1914,7 @@ struct input_dev *input_allocate_device(void) * when we register the device. */ dev->max_vals = 10; - dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); + dev->vals = kzalloc_objs(*dev->vals, dev->max_vals); if (!dev->vals) { kfree(dev); return NULL; @@ -2223,7 +2206,7 @@ static void __input_unregister_device(struct input_dev *dev) handle->handler->disconnect(handle); WARN_ON(!list_empty(&dev->h_list)); - del_timer_sync(&dev->timer); + timer_delete_sync(&dev->timer); list_del_init(&dev->node); input_wakeup_procfs_readers(); @@ -2249,7 +2232,7 @@ static void devm_input_device_unregister(struct device *dev, void *res) */ static void input_repeat_key(struct timer_list *t) { - struct input_dev *dev = from_timer(dev, t, timer); + struct input_dev *dev = timer_container_of(dev, t, timer); guard(spinlock_irqsave)(&dev->event_lock); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index ba2b17288bcd..32459fd8a7c1 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -261,7 +261,7 @@ static int joydev_open(struct inode *inode, struct file *file) struct joydev_client *client; int error; - client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); + client = kzalloc_obj(struct joydev_client); if (!client) return -ENOMEM; @@ -921,7 +921,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, return error; } - joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); + joydev = kzalloc_obj(struct joydev); if (!joydev) { error = -ENOMEM; goto err_free_minor; diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 15182f16ed19..48a1457961ef 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -249,7 +249,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - a3d = kzalloc(sizeof(*a3d), GFP_KERNEL); + a3d = kzalloc_obj(*a3d); input_dev = input_allocate_device(); if (!a3d || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 963250de24b7..e07b71978509 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -456,7 +456,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - port = kzalloc(sizeof(*port), GFP_KERNEL); + port = kzalloc_obj(*port); if (!port) return -ENOMEM; diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index c709b58d770a..b6f7bce1c14f 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -582,7 +582,7 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv int i; int err; - port = kzalloc(sizeof(*port), GFP_KERNEL); + port = kzalloc_obj(*port); if (!port) return -ENOMEM; diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 49a0dfbbeb49..7b4d61626898 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -237,7 +237,7 @@ static int as5011_probe(struct i2c_client *client) return -ENODEV; } - as5011 = kmalloc(sizeof(*as5011), GFP_KERNEL); + as5011 = kmalloc_obj(*as5011); input_dev = input_allocate_device(); if (!as5011 || !input_dev) { dev_err(&client->dev, diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 5a0ea3ad5efa..ffa6d49c81fe 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -141,7 +141,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) int i, j; int err; - cobra = kzalloc(sizeof(*cobra), GFP_KERNEL); + cobra = kzalloc_obj(*cobra); if (!cobra) return -ENOMEM; diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index a9f1946cf0d6..e5d9b71aab99 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -351,7 +351,7 @@ static int db9_saturn(int mode, struct parport *port, struct input_dev *devs[]) static void db9_timer(struct timer_list *t) { - struct db9 *db9 = from_timer(db9, t, timer); + struct db9 *db9 = timer_container_of(db9, t, timer); struct parport *port = db9->pd->port; struct input_dev *dev = db9->dev[0]; struct input_dev *dev2 = db9->dev[1]; @@ -531,7 +531,7 @@ static void db9_close(struct input_dev *dev) guard(mutex)(&db9->mutex); if (!--db9->used) { - del_timer_sync(&db9->timer); + timer_delete_sync(&db9->timer); parport_write_control(port, 0x00); parport_data_forward(port); parport_release(db9->pd); @@ -585,7 +585,7 @@ static void db9_attach(struct parport *pp) return; } - db9 = kzalloc(sizeof(*db9), GFP_KERNEL); + db9 = kzalloc_obj(*db9); if (!db9) goto err_unreg_pardev; diff --git a/drivers/input/joystick/fsia6b.c b/drivers/input/joystick/fsia6b.c index 76ffdec5c183..b0d73648477e 100644 --- a/drivers/input/joystick/fsia6b.c +++ b/drivers/input/joystick/fsia6b.c @@ -132,7 +132,7 @@ static int fsia6b_serio_connect(struct serio *serio, struct serio_driver *drv) int i, j; int sw_id = 0; - fsia6b = kzalloc(sizeof(*fsia6b), GFP_KERNEL); + fsia6b = kzalloc_obj(*fsia6b); if (!fsia6b) return -ENOMEM; @@ -149,7 +149,7 @@ static int fsia6b_serio_connect(struct serio *serio, struct serio_driver *drv) } fsia6b->dev = input_dev; - snprintf(fsia6b->phys, sizeof(fsia6b->phys), "%s/input0", serio->phys); + scnprintf(fsia6b->phys, sizeof(fsia6b->phys), "%s/input0", serio->phys); input_dev->name = DRIVER_DESC; input_dev->phys = fsia6b->phys; diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index b53cafd7a5ee..d84d453b51af 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -291,7 +291,7 @@ static int gc_n64_init_ff(struct input_dev *dev, int i) struct gc_subdev *sdev; int err; - sdev = kmalloc(sizeof(*sdev), GFP_KERNEL); + sdev = kmalloc_obj(*sdev); if (!sdev) return -ENOMEM; @@ -726,7 +726,7 @@ static void gc_psx_process_packet(struct gc *gc) static void gc_timer(struct timer_list *t) { - struct gc *gc = from_timer(gc, t, timer); + struct gc *gc = timer_container_of(gc, t, timer); /* * N64 pads - must be read first, any read confuses them for 200 us @@ -786,7 +786,7 @@ static void gc_close(struct input_dev *dev) guard(mutex)(&gc->mutex); if (!--gc->used) { - del_timer_sync(&gc->timer); + timer_delete_sync(&gc->timer); parport_write_control(gc->pd->port, 0x00); parport_release(gc->pd); } @@ -948,7 +948,7 @@ static void gc_attach(struct parport *pp) return; } - gc = kzalloc(sizeof(*gc), GFP_KERNEL); + gc = kzalloc_obj(*gc); if (!gc) { pr_err("Not enough memory\n"); goto err_unreg_pardev; diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index e7ff7bdb1a3a..1d843115d674 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -165,8 +165,10 @@ static void gf2k_read(struct gf2k *gf2k, unsigned char *data) t = GB(40,4,0); - for (i = 0; i < gf2k_hats[gf2k->id]; i++) - input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); + if (t < ARRAY_SIZE(gf2k_hat_to_axis)) + for (i = 0; i < gf2k_hats[gf2k->id]; i++) + input_report_abs(dev, ABS_HAT0X + i, + gf2k_hat_to_axis[t][i]); t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); @@ -222,7 +224,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) unsigned char data[GF2K_LENGTH]; int i, err; - gf2k = kzalloc(sizeof(*gf2k), GFP_KERNEL); + gf2k = kzalloc_obj(*gf2k); input_dev = input_allocate_device(); if (!gf2k || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index f339ce2b7a33..2a3f768a7218 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -284,7 +284,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) int i, j, t; int err; - grip = kzalloc(sizeof(*grip), GFP_KERNEL); + grip = kzalloc_obj(*grip); if (!grip) return -ENOMEM; diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c index 5eadb5a3ca37..62fdd0831c83 100644 --- a/drivers/input/joystick/grip_mp.c +++ b/drivers/input/joystick/grip_mp.c @@ -632,7 +632,7 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) struct grip_mp *grip; int err; - grip = kzalloc(sizeof(*grip), GFP_KERNEL); + grip = kzalloc_obj(*grip); if (!grip) return -ENOMEM; diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 1c5a76f72239..13f0fa4d3938 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -163,7 +163,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver * int i, t; int err; - guillemot = kzalloc(sizeof(*guillemot), GFP_KERNEL); + guillemot = kzalloc_obj(*guillemot); input_dev = input_allocate_device(); if (!guillemot || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 55e6321adab9..86d09faa685c 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -6,6 +6,7 @@ * USB/RS232 I-Force joysticks and wheels. */ +#include <linux/export.h> #include <linux/unaligned.h> #include "iforce.h" diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c index 74181d5123cd..fd1cd731d781 100644 --- a/drivers/input/joystick/iforce/iforce-packets.c +++ b/drivers/input/joystick/iforce/iforce-packets.c @@ -6,6 +6,7 @@ * USB/RS232 I-Force joysticks and wheels. */ +#include <linux/export.h> #include <linux/unaligned.h> #include "iforce.h" diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 75b85c46dfa4..e235834888d2 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -185,7 +185,7 @@ static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) struct iforce_serio *iforce_serio; int err; - iforce_serio = kzalloc(sizeof(*iforce_serio), GFP_KERNEL); + iforce_serio = kzalloc_obj(*iforce_serio); if (!iforce_serio) return -ENOMEM; diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c index 1f00f76b0174..0482eaaecf39 100644 --- a/drivers/input/joystick/iforce/iforce-usb.c +++ b/drivers/input/joystick/iforce/iforce-usb.c @@ -207,7 +207,7 @@ static int iforce_usb_probe(struct usb_interface *intf, if (!usb_endpoint_is_int_out(epout)) return -ENODEV; - iforce_usb = kzalloc(sizeof(*iforce_usb), GFP_KERNEL); + iforce_usb = kzalloc_obj(*iforce_usb); if (!iforce_usb) goto fail; diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index 262f022e5695..507cec36b220 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -192,7 +192,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d int i, t; int err; - interact = kzalloc(sizeof(*interact), GFP_KERNEL); + interact = kzalloc_obj(*interact); input_dev = input_allocate_device(); if (!interact || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c index 865652a7821d..c9cbdcc7f31f 100644 --- a/drivers/input/joystick/joydump.c +++ b/drivers/input/joystick/joydump.c @@ -61,7 +61,7 @@ static int joydump_connect(struct gameport *gameport, struct gameport_driver *dr timeout = gameport_time(gameport, 10000); /* 10 ms */ - buf = kmalloc_array(BUF_SIZE, sizeof(struct joydump), GFP_KERNEL); + buf = kmalloc_objs(struct joydump, BUF_SIZE); if (!buf) { printk(KERN_INFO "joydump: no memory for testing\n"); goto jd_end; diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index 2eaa25c9c68c..201a049c8c06 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -48,7 +48,7 @@ struct magellan { static int magellan_crunch_nibbles(unsigned char *data, int count) { - static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?"; + static const unsigned char nibbles[16] __nonstring = "0AB3D56GH9:K<MN?"; do { if (data[count] == nibbles[data[count] & 0xf]) @@ -132,7 +132,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - magellan = kzalloc(sizeof(*magellan), GFP_KERNEL); + magellan = kzalloc_obj(*magellan); input_dev = input_allocate_device(); if (!magellan || !input_dev) goto fail1; diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c index 8b54f9b18e7c..7f36f73844a9 100644 --- a/drivers/input/joystick/maplecontrol.c +++ b/drivers/input/joystick/maplecontrol.c @@ -102,7 +102,7 @@ static int probe_maple_controller(struct device *dev) struct input_dev *idev; unsigned long data = be32_to_cpu(mdev->devinfo.function_data[0]); - pad = kzalloc(sizeof(*pad), GFP_KERNEL); + pad = kzalloc_obj(*pad); idev = input_allocate_device(); if (!pad || !idev) { error = -ENOMEM; diff --git a/drivers/input/joystick/n64joy.c b/drivers/input/joystick/n64joy.c index c344dbc0c493..43a02bb99fc2 100644 --- a/drivers/input/joystick/n64joy.c +++ b/drivers/input/joystick/n64joy.c @@ -216,7 +216,7 @@ static void n64joy_close(struct input_dev *dev) guard(mutex)(&priv->n64joy_mutex); if (!--priv->n64joy_opened) - del_timer_sync(&priv->timer); + timer_delete_sync(&priv->timer); } static const u64 __initconst scandata[] ____cacheline_aligned = { @@ -243,7 +243,7 @@ static int __init n64joy_probe(struct platform_device *pdev) int err = 0; u32 i, j, found = 0; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; mutex_init(&priv->n64joy_mutex); diff --git a/drivers/input/joystick/psxpad-spi.c b/drivers/input/joystick/psxpad-spi.c index c47fc5f34bd0..f902a56d011f 100644 --- a/drivers/input/joystick/psxpad-spi.c +++ b/drivers/input/joystick/psxpad-spi.c @@ -344,7 +344,11 @@ static int psxpad_spi_probe(struct spi_device *spi) /* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */ spi->controller->min_speed_hz = 125000; spi->controller->max_speed_hz = 125000; - spi_setup(spi); + err = spi_setup(spi); + if (err) { + dev_err(&spi->dev, "failed to set up SPI: %d\n", err); + return err; + } /* pad settings */ psxpad_set_motor_level(pad, 0, 0); diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index 3a5873e5fcb3..7f37d18c8477 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -578,7 +578,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) comment[0] = 0; - sw = kzalloc(sizeof(*sw), GFP_KERNEL); + sw = kzalloc_obj(*sw); buf = kmalloc(SW_LENGTH, GFP_KERNEL); idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); if (!sw || !buf || !idbuf) { diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 4f2221001a95..1af299a41d13 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -199,7 +199,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv) if ((id = serio->id.id) > SPACEBALL_MAX_ID) return -ENODEV; - spaceball = kmalloc(sizeof(*spaceball), GFP_KERNEL); + spaceball = kmalloc_obj(*spaceball); input_dev = input_allocate_device(); if (!spaceball || !input_dev) goto fail1; diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 7250d74d62a1..ba5b318993ec 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -147,7 +147,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - spaceorb = kzalloc(sizeof(*spaceorb), GFP_KERNEL); + spaceorb = kzalloc_obj(*spaceorb); input_dev = input_allocate_device(); if (!spaceorb || !input_dev) goto fail1; diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 1b24ea21aa30..011f9b137dca 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -118,7 +118,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err = -ENOMEM; - stinger = kmalloc(sizeof(*stinger), GFP_KERNEL); + stinger = kmalloc_obj(*stinger); input_dev = input_allocate_device(); if (!stinger || !input_dev) goto fail1; diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 514b1026e379..d419f41e62ac 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -264,7 +264,7 @@ static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) int i, j, b = 0; int err; - tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL); + tmdc->port[idx] = port = kzalloc_obj(struct tmdc_port); input_dev = input_allocate_device(); if (!port || !input_dev) { err = -ENOMEM; @@ -348,7 +348,7 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) int i; int err; - tmdc = kzalloc(sizeof(*tmdc), GFP_KERNEL); + tmdc = kzalloc_obj(*tmdc); if (!tmdc) return -ENOMEM; diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index db696ba61a3b..4ee45f27290a 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -72,7 +72,7 @@ static struct tgfx { static void tgfx_timer(struct timer_list *t) { - struct tgfx *tgfx = from_timer(tgfx, t, timer); + struct tgfx *tgfx = timer_container_of(tgfx, t, timer); struct input_dev *dev; int data1, data2, i; @@ -124,7 +124,7 @@ static void tgfx_close(struct input_dev *dev) guard(mutex)(&tgfx->sem); if (!--tgfx->used) { - del_timer_sync(&tgfx->timer); + timer_delete_sync(&tgfx->timer); parport_write_control(tgfx->pd->port, 0x00); parport_release(tgfx->pd); } @@ -170,7 +170,7 @@ static void tgfx_attach(struct parport *pp) return; } - tgfx = kzalloc(sizeof(*tgfx), GFP_KERNEL); + tgfx = kzalloc_obj(*tgfx); if (!tgfx) { printk(KERN_ERR "turbografx.c: Not enough memory\n"); goto err_unreg_pardev; diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index ab99d76e5d8d..fb452552ceb2 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -171,7 +171,7 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - twidjoy = kzalloc(sizeof(*twidjoy), GFP_KERNEL); + twidjoy = kzalloc_obj(*twidjoy); input_dev = input_allocate_device(); if (!twidjoy || !input_dev) goto fail1; diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index 59eea813f258..15370fb82317 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -232,8 +232,7 @@ static void walkera0701_attach(struct parport *pp) goto err_unregister_device; } - hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - w->timer.function = timer_handler; + hrtimer_setup(&w->timer, timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL); w->input_dev = input_allocate_device(); if (!w->input_dev) { diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index ebeab441e9ec..2e1c6df98e24 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -124,7 +124,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err = -ENOMEM; - warrior = kzalloc(sizeof(*warrior), GFP_KERNEL); + warrior = kzalloc_obj(*warrior); input_dev = input_allocate_device(); if (!warrior || !input_dev) goto fail1; diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index c33e6f33265b..feb8f368f834 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -25,40 +25,6 @@ * - Greg Kroah-Hartman - usb-skeleton driver * - Xbox Linux project - extra USB IDs * - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering - * - * TODO: - * - fine tune axes (especially trigger axes) - * - fix "analog" buttons (reported as digital now) - * - get rumble working - * - need USB IDs for other dance pads - * - * History: - * - * 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller" - * - * 2002-07-02 - 0.0.2 : basic working version - * - all axes and 9 of the 10 buttons work (german InterAct device) - * - the black button does not work - * - * 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik - * - indentation fixes - * - usb + input init sequence fixes - * - * 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3 - * - verified the lack of HID and report descriptors - * - verified that ALL buttons WORK - * - fixed d-pad to axes mapping - * - * 2002-07-17 - 0.0.5 : simplified d-pad handling - * - * 2004-10-02 - 0.0.6 : DDR pad support - * - borrowed from the Xbox Linux kernel - * - USB id's for commonly used dance pads are present - * - dance pads will map D-PAD to buttons, not axes - * - pass the module paramater 'dpad_to_buttons' to force - * the D-PAD to map to buttons if your pad is not detected - * - * Later changes can be tracked in SCM. */ #include <linux/bits.h> @@ -77,12 +43,13 @@ * xbox d-pads should map to buttons, as is required for DDR pads * but we map them to axes when possible to simplify things */ -#define MAP_DPAD_TO_BUTTONS (1 << 0) -#define MAP_TRIGGERS_TO_BUTTONS (1 << 1) -#define MAP_STICKS_TO_NULL (1 << 2) -#define MAP_SELECT_BUTTON (1 << 3) -#define MAP_PADDLES (1 << 4) -#define MAP_PROFILE_BUTTON (1 << 5) +#define MAP_DPAD_TO_BUTTONS BIT(0) +#define MAP_TRIGGERS_TO_BUTTONS BIT(1) +#define MAP_STICKS_TO_NULL BIT(2) +#define MAP_SHARE_BUTTON BIT(3) +#define MAP_PADDLES BIT(4) +#define MAP_PROFILE_BUTTON BIT(5) +#define MAP_SHARE_OFFSET BIT(6) #define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \ MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL) @@ -104,6 +71,8 @@ #define PKT_XBE2_FW_5_EARLY 3 #define PKT_XBE2_FW_5_11 4 +#define FLAG_DELAY_INIT BIT(0) + static bool dpad_to_buttons; module_param(dpad_to_buttons, bool, S_IRUGO); MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); @@ -126,23 +95,26 @@ static const struct xpad_device { char *name; u8 mapping; u8 xtype; + u8 flags; } xpad_device[] = { /* Please keep this list sorted by vendor and product ID. */ { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, + { 0x0351, 0x1000, "CRKD LP Blueberry Burst Pro Edition (Xbox)", 0, XTYPE_XBOX360 }, + { 0x0351, 0x2000, "CRKD LP Black Tribal Edition (Xbox) ", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff02, "Wooting Two (Legacy)", 0, XTYPE_XBOX360 }, { 0x03f0, 0x038D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wired */ { 0x03f0, 0x048D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wireless */ { 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, { 0x03f0, 0x07A0, "HyperX Clutch Gladiate RGB", 0, XTYPE_XBOXONE }, - { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, /* v2 */ + { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, /* v2 */ { 0x03f0, 0x09B4, "HyperX Clutch Tanto", 0, XTYPE_XBOXONE }, { 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, - { 0x044f, 0xd01e, "ThrustMaster, Inc. ESWAP X 2 ELDEN RING EDITION", 0, XTYPE_XBOXONE }, { 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX }, { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 }, + { 0x044f, 0xd01e, "ThrustMaster, Inc. ESWAP X 2 ELDEN RING EDITION", 0, XTYPE_XBOXONE }, { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, @@ -159,7 +131,7 @@ static const struct xpad_device { { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE }, { 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE }, - { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, + { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SHARE_BUTTON | MAP_SHARE_OFFSET, XTYPE_XBOXONE }, { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, @@ -168,6 +140,7 @@ static const struct xpad_device { { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, { 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX }, { 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 }, + { 0x0502, 0x1305, "Acer NGR200", 0, XTYPE_XBOX360 }, { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, @@ -205,14 +178,18 @@ static const struct xpad_device { { 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 }, { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, { 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, + { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 }, { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, { 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 }, - { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE }, + { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x0b05, 0x1abb, "ASUS ROG RAIKIRI PRO", 0, XTYPE_XBOXONE }, + { 0x0b05, 0x1c91, "ASUS ROG RAIKIRI II", 0, XTYPE_XBOX360 }, + { 0x0b05, 0x1c92, "ASUS ROG RAIKIRI II WIRELESS", 0, XTYPE_XBOX360 }, + { 0x0b05, 0x1c96, "ASUS ROG RAIKIRI II XBOX", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x0b05, 0x1d04, "ASUS ROG RAIKIRI II XBOX WIRELESS", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX }, { 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, @@ -240,7 +217,7 @@ static const struct xpad_device { { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, - { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", XTYPE_XBOXONE }, + { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, @@ -281,6 +258,7 @@ static const struct xpad_device { { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x0151, "Hori Racing Wheel Overdrive for Xbox Series X", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0152, "Hori Racing Wheel Overdrive for Xbox Series X", 0, XTYPE_XBOXONE }, + { 0x0f0d, 0x01b2, "HORI Taiko No Tatsujin Drum Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, @@ -288,6 +266,8 @@ static const struct xpad_device { { 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, { 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 }, { 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE }, + { 0x10f5, 0x7008, "Turtle Beach Recon Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x10f5, 0x7073, "Turtle Beach Stealth Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 }, { 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 }, { 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 }, @@ -303,6 +283,8 @@ static const struct xpad_device { { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, { 0x1532, 0x0a29, "Razer Wolverine V2", 0, XTYPE_XBOXONE }, + { 0x1532, 0x0a57, "Razer Wolverine V3 Pro (Wired)", 0, XTYPE_XBOX360 }, + { 0x1532, 0x0a59, "Razer Wolverine V3 Pro (2.4 GHz Dongle)", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 }, @@ -350,9 +332,14 @@ static const struct xpad_device { { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 }, { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 }, { 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 }, + { 0x20bc, 0x5134, "BETOP BTP-KP50B Xinput Dongle", 0, XTYPE_XBOX360 }, + { 0x20bc, 0x514a, "BETOP BTP-KP50C Xinput Dongle", 0, XTYPE_XBOX360 }, { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, + { 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, + { 0x20d6, 0x400b, "PowerA FUSION Pro 4 Wired Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, + { 0x20d6, 0x890b, "PowerA MOGA XP-Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x2345, 0xe00b, "Machenike G5 Pro Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, @@ -384,13 +371,16 @@ static const struct xpad_device { { 0x294b, 0x3404, "Snakebyte GAMEPAD RGB X", 0, XTYPE_XBOXONE }, { 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE }, + { 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 }, + { 0x2dc8, 0x310b, "8BitDo Ultimate 2 Wireless Controller", 0, XTYPE_XBOX360 }, { 0x2dc8, 0x6001, "8BitDo SN30 Pro", 0, XTYPE_XBOX360 }, + { 0x2e24, 0x0423, "Hyperkin DuchesS Xbox One pad", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, { 0x2e24, 0x1688, "Hyperkin X91 X-Box One pad", 0, XTYPE_XBOXONE }, - { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, + { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, { 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 }, @@ -405,8 +395,12 @@ static const struct xpad_device { { 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 }, { 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE }, { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, + { 0x3537, 0x100f, "GameSir Nova 2 Lite", 0, XTYPE_XBOX360 }, { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE }, + { 0x3651, 0x1000, "CRKD SG", 0, XTYPE_XBOX360 }, + { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, + { 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 }, { 0x413d, 0x2104, "Black Shark Green Ghost Gamepad", 0, XTYPE_XBOX360 }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } @@ -427,8 +421,8 @@ static const signed short xpad_btn[] = { /* used when dpad is mapped to buttons */ static const signed short xpad_btn_pad[] = { - BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */ - BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */ + BTN_DPAD_LEFT, BTN_DPAD_RIGHT, /* d-pad left, right */ + BTN_DPAD_UP, BTN_DPAD_DOWN, /* d-pad up, down */ -1 /* terminating entry */ }; @@ -464,8 +458,8 @@ static const signed short xpad_abs_triggers[] = { /* used when the controller has extra paddle buttons */ static const signed short xpad_btn_paddles[] = { - BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */ - BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */ + BTN_GRIPR, BTN_GRIPR2, /* paddle upper right, lower right */ + BTN_GRIPL, BTN_GRIPL2, /* paddle upper left, lower left */ -1 /* terminating entry */ }; @@ -502,6 +496,7 @@ static const struct usb_device_id xpad_table[] = { */ { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ + XPAD_XBOX360_VENDOR(0x0351), /* CRKD Controllers */ XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ XPAD_XBOX360_VENDOR(0x03f0), /* HP HyperX Xbox 360 controllers */ XPAD_XBOXONE_VENDOR(0x03f0), /* HP HyperX Xbox One controllers */ @@ -510,12 +505,14 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x045e), /* Microsoft Xbox 360 controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft Xbox One controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech Xbox 360-style controllers */ + XPAD_XBOX360_VENDOR(0x0502), /* Acer Inc. Xbox 360 style controllers */ XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */ XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz Xbox 360 controllers */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */ + XPAD_XBOX360_VENDOR(0x0b05), /* ASUS controllers */ XPAD_XBOXONE_VENDOR(0x0b05), /* ASUS controllers */ XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0db0), /* Micro Star International X-Box 360 controllers */ @@ -541,6 +538,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */ XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */ XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */ + XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */ XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */ XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */ XPAD_XBOX360_VENDOR(0x2345), /* Machenike Controllers */ @@ -561,6 +559,10 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */ XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ + XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */ + XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */ + XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */ + XPAD_XBOX360_VENDOR(0x3958), /* RedOctane Games Controllers */ XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */ { } }; @@ -589,6 +591,7 @@ struct xboxone_init_packet { * - https://github.com/medusalix/xone/blob/master/bus/protocol.c */ #define GIP_CMD_ACK 0x01 +#define GIP_CMD_ANNOUNCE 0x02 #define GIP_CMD_IDENTIFY 0x04 #define GIP_CMD_POWER 0x05 #define GIP_CMD_AUTHENTICATE 0x06 @@ -663,20 +666,19 @@ static const u8 xboxone_hori_ack_id[] = { }; /* - * This packet is required for most (all?) of the PDP pads to start - * sending input reports. These pads include: (0x0e6f:0x02ab), - * (0x0e6f:0x02a4), (0x0e6f:0x02a6). + * This packet is sent by default on Windows, and is required for some pads to + * start sending input reports, including most (all?) of the PDP. These pads + * include: (0x0e6f:0x02ab), (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_led_on[] = { - GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 -}; +static const u8 xboxone_led_on[] = { GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, +GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 }; /* * This packet is required for most (all?) of the PDP pads to start * sending input reports. These pads include: (0x0e6f:0x02ab), * (0x0e6f:0x02a4), (0x0e6f:0x02a6). */ -static const u8 xboxone_pdp_auth[] = { +static const u8 xboxone_auth_done[] = { GIP_CMD_AUTHENTICATE, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(2), 0x01, 0x00 }; @@ -713,10 +715,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = { XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init), XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on), - XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_led_on), - XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth), - XBOXONE_INIT_PKT(0x20d6, 0xa01a, xboxone_pdp_auth), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_led_on), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_auth_done), XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init), XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init), @@ -776,10 +776,13 @@ struct usb_xpad { const char *name; /* name of the device */ struct work_struct work; /* init/remove device from callback */ time64_t mode_btn_down_ts; + bool delay_init; /* init packets should be delayed */ + bool delayed_init_done; }; static int xpad_init_input(struct usb_xpad *xpad); static void xpad_deinit_input(struct usb_xpad *xpad); +static int xpad_start_input(struct usb_xpad *xpad); static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num); static void xpad360w_poweroff_controller(struct usb_xpad *xpad); @@ -822,10 +825,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); + input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2)); + input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3)); + input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0)); + input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1)); } else { input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); @@ -873,10 +876,10 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev, /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3)); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1)); + input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2)); + input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3)); + input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0)); + input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1)); } /* @@ -1027,7 +1030,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha * The report format was gleaned from * https://github.com/kylelemons/xbox/blob/master/xbox.go */ -static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) +static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, u32 len) { struct input_dev *dev = xpad->dev; bool do_sync = false; @@ -1057,19 +1060,34 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[18] = 0; /* Elite Series 2 split packet paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); + input_report_key(dev, BTN_GRIPR, data[18] & BIT(0)); + input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1)); + input_report_key(dev, BTN_GRIPL, data[18] & BIT(2)); + input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3)); do_sync = true; } + } else if (data[0] == GIP_CMD_ANNOUNCE) { + int error; + + if (xpad->delay_init && !xpad->delayed_init_done) { + xpad->delayed_init_done = true; + error = xpad_start_input(xpad); + if (error) + dev_warn(&xpad->dev->dev, + "unable to start delayed input: %d\n", + error); + } } else if (data[0] == GIP_CMD_INPUT) { /* The main valid packet type for inputs */ /* menu/view buttons */ input_report_key(dev, BTN_START, data[4] & BIT(2)); input_report_key(dev, BTN_SELECT, data[4] & BIT(3)); - if (xpad->mapping & MAP_SELECT_BUTTON) - input_report_key(dev, KEY_RECORD, data[22] & BIT(0)); + if (xpad->mapping & MAP_SHARE_BUTTON) { + u32 offset = (xpad->mapping & MAP_SHARE_OFFSET) ? 26 : 18; + + if (len >= offset) + input_report_key(dev, KEY_RECORD, data[len - offset] & BIT(0)); + } /* buttons A,B,X,Y */ input_report_key(dev, BTN_A, data[4] & BIT(4)); @@ -1080,10 +1098,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char /* digital pad */ if (xpad->mapping & MAP_DPAD_TO_BUTTONS) { /* dpad as buttons (left, right, up, down) */ - input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3)); - input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1)); + input_report_key(dev, BTN_DPAD_LEFT, data[5] & BIT(2)); + input_report_key(dev, BTN_DPAD_RIGHT, data[5] & BIT(3)); + input_report_key(dev, BTN_DPAD_UP, data[5] & BIT(0)); + input_report_key(dev, BTN_DPAD_DOWN, data[5] & BIT(1)); } else { input_report_abs(dev, ABS_HAT0X, !!(data[5] & 0x08) - !!(data[5] & 0x04)); @@ -1142,10 +1160,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[32] = 0; /* OG Elite Series Controller paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1)); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3)); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2)); + input_report_key(dev, BTN_GRIPR, data[32] & BIT(1)); + input_report_key(dev, BTN_GRIPR2, data[32] & BIT(3)); + input_report_key(dev, BTN_GRIPL, data[32] & BIT(0)); + input_report_key(dev, BTN_GRIPL2, data[32] & BIT(2)); } else if (xpad->packet_type == PKT_XBE2_FW_OLD) { /* Mute paddles if controller has a custom mapping applied. * Checked by comparing the current mapping @@ -1155,10 +1173,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char data[18] = 0; /* Elite Series 2 4.x firmware paddle bits */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1)); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3)); + input_report_key(dev, BTN_GRIPR, data[18] & BIT(0)); + input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1)); + input_report_key(dev, BTN_GRIPL, data[18] & BIT(2)); + input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3)); } else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) { /* Mute paddles if controller has a custom mapping applied. * Checked by comparing the current mapping @@ -1170,10 +1188,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char /* Elite Series 2 5.x firmware paddle bits * (before the packet was split) */ - input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0)); - input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1)); - input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2)); - input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3)); + input_report_key(dev, BTN_GRIPR, data[22] & BIT(0)); + input_report_key(dev, BTN_GRIPR2, data[22] & BIT(1)); + input_report_key(dev, BTN_GRIPL, data[22] & BIT(2)); + input_report_key(dev, BTN_GRIPL2, data[22] & BIT(3)); } } @@ -1217,7 +1235,7 @@ static void xpad_irq_in(struct urb *urb) xpad360w_process_packet(xpad, 0, xpad->idata); break; case XTYPE_XBOXONE: - xpadone_process_packet(xpad, 0, xpad->idata); + xpadone_process_packet(xpad, 0, xpad->idata, urb->actual_length); break; default: xpad_process_packet(xpad, 0, xpad->idata); @@ -1238,6 +1256,14 @@ static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) if (xpad->xtype != XTYPE_XBOXONE) return false; + /* + * Some dongles will discard init packets if they're sent before the + * controller connects. In these cases, we need to wait until we get + * an announce packet from them to send the init packet sequence. + */ + if (xpad->delay_init && !xpad->delayed_init_done) + return false; + /* Perform initialization sequence for Xbox One pads that require it */ while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) { init_packet = &xboxone_init_packets[xpad->init_seq++]; @@ -1305,11 +1331,12 @@ static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad) usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor); error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC); if (error) { - dev_err(&xpad->intf->dev, - "%s - usb_submit_urb failed with result %d\n", - __func__, error); + if (error != -ENODEV) + dev_err(&xpad->intf->dev, + "%s - usb_submit_urb failed with result %d\n", + __func__, error); usb_unanchor_urb(xpad->irq_out); - return -EIO; + return error; } xpad->irq_out_active = true; @@ -1695,7 +1722,7 @@ static int xpad_led_probe(struct usb_xpad *xpad) if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W) return 0; - xpad->led = led = kzalloc(sizeof(*led), GFP_KERNEL); + xpad->led = led = kzalloc_obj(*led); if (!led) return -ENOMEM; @@ -1944,7 +1971,7 @@ static int xpad_init_input(struct usb_xpad *xpad) xpad->xtype == XTYPE_XBOXONE) { for (i = 0; xpad360_btn[i] >= 0; i++) input_set_capability(input_dev, EV_KEY, xpad360_btn[i]); - if (xpad->mapping & MAP_SELECT_BUTTON) + if (xpad->mapping & MAP_SHARE_BUTTON) input_set_capability(input_dev, EV_KEY, KEY_RECORD); } else { for (i = 0; xpad_btn[i] >= 0; i++) @@ -2028,7 +2055,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id break; } - xpad = kzalloc(sizeof(*xpad), GFP_KERNEL); + xpad = kzalloc_obj(*xpad); if (!xpad) return -ENOMEM; @@ -2053,6 +2080,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id xpad->mapping = xpad_device[i].mapping; xpad->xtype = xpad_device[i].xtype; xpad->name = xpad_device[i].name; + if (xpad_device[i].flags & FLAG_DELAY_INIT) + xpad->delay_init = true; + xpad->packet_type = PKT_XB; INIT_WORK(&xpad->work, xpad_presence_work); @@ -2252,6 +2282,7 @@ static int xpad_resume(struct usb_interface *intf) struct usb_xpad *xpad = usb_get_intfdata(intf); struct input_dev *input = xpad->dev; + xpad->delayed_init_done = false; if (xpad->xtype == XTYPE_XBOX360W) return xpad360w_start_input(xpad); diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c index cc0e2a77ac5e..8ca1896639de 100644 --- a/drivers/input/joystick/zhenhua.c +++ b/drivers/input/joystick/zhenhua.c @@ -131,7 +131,7 @@ static int zhenhua_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err = -ENOMEM; - zhenhua = kzalloc(sizeof(*zhenhua), GFP_KERNEL); + zhenhua = kzalloc_obj(*zhenhua); input_dev = input_allocate_device(); if (!zhenhua || !input_dev) goto fail1; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 721ab69e84ac..9d1019ba0245 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -37,6 +37,17 @@ config KEYBOARD_ADP5520 To compile this driver as a module, choose M here: the module will be called adp5520-keys. +config KEYBOARD_ADP5585 + tristate "ADP558x keypad support" + depends on MFD_ADP5585 + select INPUT_MATRIXKMAP + help + This option enables support for the KEYPAD function found in the Analog + Devices ADP5585 and similar devices. + + To compile this driver as a module, choose M here: the + module will be called adp5585-keys. + config KEYBOARD_ADP5588 tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander" depends on I2C @@ -50,16 +61,6 @@ config KEYBOARD_ADP5588 To compile this driver as a module, choose M here: the module will be called adp5588-keys. -config KEYBOARD_ADP5589 - tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander" - depends on I2C - help - Say Y here if you want to use a ADP5585/ADP5589 attached to your - system I2C bus. - - To compile this driver as a module, choose M here: the - module will be called adp5589-keys. - config KEYBOARD_AMIGA tristate "Amiga keyboard" depends on AMIGA @@ -261,24 +262,6 @@ config KEYBOARD_GPIO_POLLED To compile this driver as a module, choose M here: the module will be called gpio_keys_polled. -config KEYBOARD_TCA6416 - tristate "TCA6416/TCA6408A Keypad Support" - depends on I2C - help - This driver implements basic keypad functionality - for keys connected through TCA6416/TCA6408A IO expanders. - - Say Y here if your device has keys connected to - TCA6416/TCA6408A IO expander. Your board-specific setup logic - must also provide pin-mask details(of which TCA6416 pins - are used for keypad). - - If enabled the entire TCA6416 device will be managed through - this driver. - - To compile this driver as a module, choose M here: the - module will be called tca6416_keypad. - config KEYBOARD_TCA8418 tristate "TCA8418 Keypad Support" depends on I2C @@ -306,6 +289,20 @@ config KEYBOARD_MATRIX To compile this driver as a module, choose M here: the module will be called matrix_keypad. +config KEYBOARD_CHARLIEPLEX + tristate "GPIO driven charlieplex keypad support" + depends on GPIOLIB || COMPILE_TEST + select INPUT_MATRIXKMAP + help + Enable support for GPIO driven charlieplex keypad. A charlieplex + keypad allows to use fewer GPIO lines to interface to key switches. + For example, an N lines charlieplex keypad can be used to interface + to N^2-N different key switches. However, this type of keypad + cannot detect more than one key press at a time. + + To compile this driver as a module, choose M here: the + module will be called charlieplex_keypad. + config KEYBOARD_HIL_OLD tristate "HP HIL keyboard support (simple driver)" depends on GSC || HP300 @@ -421,6 +418,18 @@ config KEYBOARD_MAX7359 To compile this driver as a module, choose M here: the module will be called max7359_keypad. +config KEYBOARD_MAX7360 + tristate "Maxim MAX7360 Key Switch Controller" + select INPUT_MATRIXKMAP + depends on I2C + depends on MFD_MAX7360 + help + If you say yes here you get support for the keypad controller on the + Maxim MAX7360 I/O Expander. + + To compile this driver as a module, choose M here: the module will be + called max7360_keypad. + config KEYBOARD_MPR121 tristate "Freescale MPR121 Touchkey" depends on I2C diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 1e0721c30709..60bb7baf802f 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -7,14 +7,15 @@ obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o +obj-$(CONFIG_KEYBOARD_ADP5585) += adp5585-keys.o obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o -obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o +obj-$(CONFIG_KEYBOARD_CHARLIEPLEX) += charlieplex_keypad.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o @@ -23,7 +24,6 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o -obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o @@ -42,6 +42,7 @@ obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o +obj-$(CONFIG_KEYBOARD_MAX7360) += max7360-keypad.o obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o diff --git a/drivers/input/keyboard/adp5585-keys.c b/drivers/input/keyboard/adp5585-keys.c new file mode 100644 index 000000000000..4208229e1356 --- /dev/null +++ b/drivers/input/keyboard/adp5585-keys.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 Keys driver + * + * Copyright (C) 2025 Analog Devices, Inc. + */ + +#include <linux/bitmap.h> +#include <linux/container_of.h> +#include <linux/device.h> +#include <linux/find.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/mfd/adp5585.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/notifier.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/types.h> + +/* As needed for the matrix parsing code */ +#define ADP5589_MAX_KEYMAPSIZE 123 + +struct adp5585_kpad_chip { + u8 key_ev_min; + u8 key_ev_max; + u8 max_rows; + u8 max_cols; +}; + +struct adp5585_kpad { + const struct adp5585_kpad_chip *info; + struct notifier_block nb; + struct input_dev *input; + unsigned short keycode[ADP5589_MAX_KEYMAPSIZE]; + struct device *dev; + unsigned long keypad; + int row_shift; +}; + +static int adp5585_keys_validate_events(const struct adp5585_kpad *kpad, + const u32 *events, u32 n_events) +{ + unsigned int ev; + u32 row, col; + + for (ev = 0; ev < n_events; ev++) { + if (events[ev] < kpad->info->key_ev_min || + events[ev] > kpad->info->key_ev_max) + continue; + + /* + * if the event is to be generated by the keymap, we need to make + * sure that the pins are part of it! + */ + row = (events[ev] - 1) / kpad->info->max_cols; + col = (events[ev] - 1) % kpad->info->max_cols; + + if (test_bit(row, &kpad->keypad) && + test_bit(col + kpad->info->max_rows, &kpad->keypad)) + continue; + + return dev_err_probe(kpad->dev, -EINVAL, + "Invalid unlock/reset event(%u) not used in the keypad\n", + events[ev]); + } + + return 0; +} + +static int adp5585_keys_check_special_events(const struct adp5585_dev *adp5585, + const struct adp5585_kpad *kpad) +{ + int error; + + error = adp5585_keys_validate_events(kpad, adp5585->unlock_keys, + adp5585->nkeys_unlock); + if (error) + return error; + + error = adp5585_keys_validate_events(kpad, adp5585->reset1_keys, + adp5585->nkeys_reset1); + if (error) + return error; + + return adp5585_keys_validate_events(kpad, adp5585->reset2_keys, + adp5585->nkeys_reset2); +} + +static void adp5585_keys_pins_free(void *data) +{ + struct adp5585_kpad *kpad = data; + struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); + unsigned int pin; + + for_each_set_bit(pin, &kpad->keypad, adp5585->n_pins) + clear_bit(pin, adp5585->pin_usage); +} + +static int adp5585_keys_parse_fw(const struct adp5585_dev *adp5585, + struct adp5585_kpad *kpad) +{ + struct device *dev = kpad->dev; + u32 cols = 0, rows = 0, pin; + int error, n_pins; + + /* + * We do not check for errors (or no value) since the input device is + * only added if this property is present in the first place. + */ + n_pins = device_property_count_u32(dev, "adi,keypad-pins"); + if (n_pins > adp5585->n_pins) + return dev_err_probe(dev, -EINVAL, + "Too many keypad pins (%d) defined (max=%d)\n", + n_pins, adp5585->n_pins); + + unsigned int *keypad_pins __free(kfree) = kcalloc(n_pins, sizeof(*keypad_pins), + GFP_KERNEL); + if (!keypad_pins) + return -ENOMEM; + + error = device_property_read_u32_array(dev, "adi,keypad-pins", + keypad_pins, n_pins); + if (error) + return error; + + /* + * We can add the action here since it makes the code easier and nothing + * "bad" will happen out of it. Worst case, it will be a no-op and no + * bit will set. + */ + error = devm_add_action_or_reset(dev, adp5585_keys_pins_free, kpad); + if (error) + return error; + + for (pin = 0; pin < n_pins; pin++) { + if (keypad_pins[pin] >= adp5585->n_pins) + return dev_err_probe(dev, -EINVAL, + "Invalid keypad pin(%u) defined\n", + keypad_pins[pin]); + + if (test_and_set_bit(keypad_pins[pin], adp5585->pin_usage)) + return dev_err_probe(dev, -EBUSY, + "Keypad pin(%u) already used\n", + keypad_pins[pin]); + + __set_bit(keypad_pins[pin], &kpad->keypad); + } + + /* + * Note that given that we get a mask (and the HW allows it), we + * can have holes in our keypad (eg: row0, row1 and row7 enabled). + * However, for the matrix parsing functions we need to pass the + * number of rows/cols as the maximum row/col used plus 1. This + * pretty much means we will also have holes in our SW keypad. + */ + + rows = find_last_bit(&kpad->keypad, kpad->info->max_rows) + 1; + if (rows == kpad->info->max_rows + 1) + return dev_err_probe(dev, -EINVAL, + "Now rows defined in the keypad!\n"); + + cols = find_last_bit(&kpad->keypad, kpad->info->max_cols + kpad->info->max_rows); + if (cols < kpad->info->max_rows) + return dev_err_probe(dev, -EINVAL, + "No columns defined in the keypad!\n"); + + cols = cols + 1 - kpad->info->max_rows; + + error = matrix_keypad_build_keymap(NULL, NULL, rows, cols, + kpad->keycode, kpad->input); + if (error) + return error; + + kpad->row_shift = get_count_order(cols); + + if (device_property_read_bool(kpad->dev, "autorepeat")) + __set_bit(EV_REP, kpad->input->evbit); + + error = adp5585_keys_check_special_events(adp5585, kpad); + if (error) + return error; + + return 0; +} + +static int adp5585_keys_setup(const struct adp5585_dev *adp5585, + struct adp5585_kpad *kpad) +{ + unsigned long keys_bits, start = 0, nbits = kpad->info->max_rows; + const struct adp5585_regs *regs = adp5585->regs; + unsigned int i = 0, max_cols = kpad->info->max_cols; + int error; + + /* + * Take care as the below assumes max_rows is always less or equal than + * 8 which is true for the supported devices. If we happen to add + * another device we need to make sure this still holds true. Although + * adding a new device is very unlikely. + */ + do { + keys_bits = bitmap_read(&kpad->keypad, start, nbits); + if (keys_bits) { + error = regmap_write(adp5585->regmap, regs->pin_cfg_a + i, + keys_bits); + if (error) + return error; + } + + start += nbits; + if (max_cols > 8) { + nbits = 8; + max_cols -= nbits; + } else { + nbits = max_cols; + } + + i++; + } while (start < kpad->info->max_rows + kpad->info->max_cols); + + return 0; +} + +static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key, + void *data) +{ + struct adp5585_kpad *kpad = container_of(nb, struct adp5585_kpad, nb); + unsigned long key_press = (unsigned long)data; + unsigned int row, col, code; + + /* make sure the event is for us */ + if (key < kpad->info->key_ev_min || key > kpad->info->key_ev_max) + return NOTIFY_DONE; + + /* + * Unlikely but lets be on the safe side! We do not return any error + * because the event was indeed for us but with some weird value. So, + * we still want the caller know that the right handler was called. + */ + if (!key) + return NOTIFY_BAD; + + row = (key - 1) / (kpad->info->max_cols); + col = (key - 1) % (kpad->info->max_cols); + code = MATRIX_SCAN_CODE(row, col, kpad->row_shift); + + dev_dbg_ratelimited(kpad->dev, "report key(%lu) r(%d) c(%d) code(%d)\n", + key, row, col, kpad->keycode[code]); + + input_report_key(kpad->input, kpad->keycode[code], key_press); + input_sync(kpad->input); + + return NOTIFY_STOP; +} + +static void adp5585_keys_unreg_notifier(void *data) +{ + struct adp5585_kpad *kpad = data; + struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent); + + blocking_notifier_chain_unregister(&adp5585->event_notifier, + &kpad->nb); +} + +static int adp5585_keys_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct adp5585_kpad *kpad; + unsigned int revid; + const char *phys; + int error; + + kpad = devm_kzalloc(dev, sizeof(*kpad), GFP_KERNEL); + if (!kpad) + return -ENOMEM; + + if (!adp5585->irq) + return dev_err_probe(dev, -EINVAL, + "IRQ is mandatory for the keypad\n"); + + kpad->dev = dev; + + kpad->input = devm_input_allocate_device(dev); + if (!kpad->input) + return -ENOMEM; + + kpad->info = (const struct adp5585_kpad_chip *)id->driver_data; + if (!kpad->info) + return -ENODEV; + + error = regmap_read(adp5585->regmap, ADP5585_ID, &revid); + if (error) + return dev_err_probe(dev, error, "Failed to read device ID\n"); + + phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", pdev->name); + if (!phys) + return -ENOMEM; + + kpad->input->name = pdev->name; + kpad->input->phys = phys; + + kpad->input->id.bustype = BUS_I2C; + kpad->input->id.vendor = 0x0001; + kpad->input->id.product = 0x0001; + kpad->input->id.version = revid & ADP5585_REV_ID_MASK; + + device_set_of_node_from_dev(dev, dev->parent); + + error = adp5585_keys_parse_fw(adp5585, kpad); + if (error) + return error; + + error = adp5585_keys_setup(adp5585, kpad); + if (error) + return error; + + kpad->nb.notifier_call = adp5585_keys_ev_handle; + error = blocking_notifier_chain_register(&adp5585->event_notifier, + &kpad->nb); + if (error) + return error; + + error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad); + if (error) + return error; + + error = input_register_device(kpad->input); + if (error) + return dev_err_probe(dev, error, + "Failed to register input device\n"); + + return 0; +} + +static const struct adp5585_kpad_chip adp5585_kpad_chip_info = { + .max_rows = 6, + .max_cols = 5, + .key_ev_min = ADP5585_ROW5_KEY_EVENT_START, + .key_ev_max = ADP5585_ROW5_KEY_EVENT_END, +}; + +static const struct adp5585_kpad_chip adp5589_kpad_chip_info = { + .max_rows = 8, + .max_cols = 11, + .key_ev_min = ADP5589_KEY_EVENT_START, + .key_ev_max = ADP5589_KEY_EVENT_END, +}; + +static const struct platform_device_id adp5585_keys_id_table[] = { + { "adp5585-keys", (kernel_ulong_t)&adp5585_kpad_chip_info }, + { "adp5589-keys", (kernel_ulong_t)&adp5589_kpad_chip_info }, + { } +}; +MODULE_DEVICE_TABLE(platform, adp5585_keys_id_table); + +static struct platform_driver adp5585_keys_driver = { + .driver = { + .name = "adp5585-keys", + }, + .probe = adp5585_keys_probe, + .id_table = adp5585_keys_id_table, +}; +module_platform_driver(adp5585_keys_driver); + +MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>"); +MODULE_DESCRIPTION("ADP5585 Keys Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index dc734974ce06..414fbef4abf9 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -232,8 +232,8 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned int off) return !!(val & bit); } -static void adp5588_gpio_set_value(struct gpio_chip *chip, - unsigned int off, int val) +static int adp5588_gpio_set_value(struct gpio_chip *chip, unsigned int off, + int val) { struct adp5588_kpad *kpad = gpiochip_get_data(chip); unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]); @@ -246,7 +246,8 @@ static void adp5588_gpio_set_value(struct gpio_chip *chip, else kpad->dat_out[bank] &= ~bit; - adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, kpad->dat_out[bank]); + return adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, + kpad->dat_out[bank]); } static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off, diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c deleted file mode 100644 index 81d0876ee358..000000000000 --- a/drivers/input/keyboard/adp5589-keys.c +++ /dev/null @@ -1,1066 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Description: keypad driver for ADP5589, ADP5585 - * I2C QWERTY Keypad and IO Expander - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * Copyright (C) 2010-2011 Analog Devices Inc. - */ - -#include <linux/bitops.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/workqueue.h> -#include <linux/errno.h> -#include <linux/pm.h> -#include <linux/pm_wakeirq.h> -#include <linux/platform_device.h> -#include <linux/input.h> -#include <linux/i2c.h> -#include <linux/gpio/driver.h> -#include <linux/slab.h> - -#include <linux/input/adp5589.h> - -/* ADP5589/ADP5585 Common Registers */ -#define ADP5589_5_ID 0x00 -#define ADP5589_5_INT_STATUS 0x01 -#define ADP5589_5_STATUS 0x02 -#define ADP5589_5_FIFO_1 0x03 -#define ADP5589_5_FIFO_2 0x04 -#define ADP5589_5_FIFO_3 0x05 -#define ADP5589_5_FIFO_4 0x06 -#define ADP5589_5_FIFO_5 0x07 -#define ADP5589_5_FIFO_6 0x08 -#define ADP5589_5_FIFO_7 0x09 -#define ADP5589_5_FIFO_8 0x0A -#define ADP5589_5_FIFO_9 0x0B -#define ADP5589_5_FIFO_10 0x0C -#define ADP5589_5_FIFO_11 0x0D -#define ADP5589_5_FIFO_12 0x0E -#define ADP5589_5_FIFO_13 0x0F -#define ADP5589_5_FIFO_14 0x10 -#define ADP5589_5_FIFO_15 0x11 -#define ADP5589_5_FIFO_16 0x12 -#define ADP5589_5_GPI_INT_STAT_A 0x13 -#define ADP5589_5_GPI_INT_STAT_B 0x14 - -/* ADP5589 Registers */ -#define ADP5589_GPI_INT_STAT_C 0x15 -#define ADP5589_GPI_STATUS_A 0x16 -#define ADP5589_GPI_STATUS_B 0x17 -#define ADP5589_GPI_STATUS_C 0x18 -#define ADP5589_RPULL_CONFIG_A 0x19 -#define ADP5589_RPULL_CONFIG_B 0x1A -#define ADP5589_RPULL_CONFIG_C 0x1B -#define ADP5589_RPULL_CONFIG_D 0x1C -#define ADP5589_RPULL_CONFIG_E 0x1D -#define ADP5589_GPI_INT_LEVEL_A 0x1E -#define ADP5589_GPI_INT_LEVEL_B 0x1F -#define ADP5589_GPI_INT_LEVEL_C 0x20 -#define ADP5589_GPI_EVENT_EN_A 0x21 -#define ADP5589_GPI_EVENT_EN_B 0x22 -#define ADP5589_GPI_EVENT_EN_C 0x23 -#define ADP5589_GPI_INTERRUPT_EN_A 0x24 -#define ADP5589_GPI_INTERRUPT_EN_B 0x25 -#define ADP5589_GPI_INTERRUPT_EN_C 0x26 -#define ADP5589_DEBOUNCE_DIS_A 0x27 -#define ADP5589_DEBOUNCE_DIS_B 0x28 -#define ADP5589_DEBOUNCE_DIS_C 0x29 -#define ADP5589_GPO_DATA_OUT_A 0x2A -#define ADP5589_GPO_DATA_OUT_B 0x2B -#define ADP5589_GPO_DATA_OUT_C 0x2C -#define ADP5589_GPO_OUT_MODE_A 0x2D -#define ADP5589_GPO_OUT_MODE_B 0x2E -#define ADP5589_GPO_OUT_MODE_C 0x2F -#define ADP5589_GPIO_DIRECTION_A 0x30 -#define ADP5589_GPIO_DIRECTION_B 0x31 -#define ADP5589_GPIO_DIRECTION_C 0x32 -#define ADP5589_UNLOCK1 0x33 -#define ADP5589_UNLOCK2 0x34 -#define ADP5589_EXT_LOCK_EVENT 0x35 -#define ADP5589_UNLOCK_TIMERS 0x36 -#define ADP5589_LOCK_CFG 0x37 -#define ADP5589_RESET1_EVENT_A 0x38 -#define ADP5589_RESET1_EVENT_B 0x39 -#define ADP5589_RESET1_EVENT_C 0x3A -#define ADP5589_RESET2_EVENT_A 0x3B -#define ADP5589_RESET2_EVENT_B 0x3C -#define ADP5589_RESET_CFG 0x3D -#define ADP5589_PWM_OFFT_LOW 0x3E -#define ADP5589_PWM_OFFT_HIGH 0x3F -#define ADP5589_PWM_ONT_LOW 0x40 -#define ADP5589_PWM_ONT_HIGH 0x41 -#define ADP5589_PWM_CFG 0x42 -#define ADP5589_CLOCK_DIV_CFG 0x43 -#define ADP5589_LOGIC_1_CFG 0x44 -#define ADP5589_LOGIC_2_CFG 0x45 -#define ADP5589_LOGIC_FF_CFG 0x46 -#define ADP5589_LOGIC_INT_EVENT_EN 0x47 -#define ADP5589_POLL_PTIME_CFG 0x48 -#define ADP5589_PIN_CONFIG_A 0x49 -#define ADP5589_PIN_CONFIG_B 0x4A -#define ADP5589_PIN_CONFIG_C 0x4B -#define ADP5589_PIN_CONFIG_D 0x4C -#define ADP5589_GENERAL_CFG 0x4D -#define ADP5589_INT_EN 0x4E - -/* ADP5585 Registers */ -#define ADP5585_GPI_STATUS_A 0x15 -#define ADP5585_GPI_STATUS_B 0x16 -#define ADP5585_RPULL_CONFIG_A 0x17 -#define ADP5585_RPULL_CONFIG_B 0x18 -#define ADP5585_RPULL_CONFIG_C 0x19 -#define ADP5585_RPULL_CONFIG_D 0x1A -#define ADP5585_GPI_INT_LEVEL_A 0x1B -#define ADP5585_GPI_INT_LEVEL_B 0x1C -#define ADP5585_GPI_EVENT_EN_A 0x1D -#define ADP5585_GPI_EVENT_EN_B 0x1E -#define ADP5585_GPI_INTERRUPT_EN_A 0x1F -#define ADP5585_GPI_INTERRUPT_EN_B 0x20 -#define ADP5585_DEBOUNCE_DIS_A 0x21 -#define ADP5585_DEBOUNCE_DIS_B 0x22 -#define ADP5585_GPO_DATA_OUT_A 0x23 -#define ADP5585_GPO_DATA_OUT_B 0x24 -#define ADP5585_GPO_OUT_MODE_A 0x25 -#define ADP5585_GPO_OUT_MODE_B 0x26 -#define ADP5585_GPIO_DIRECTION_A 0x27 -#define ADP5585_GPIO_DIRECTION_B 0x28 -#define ADP5585_RESET1_EVENT_A 0x29 -#define ADP5585_RESET1_EVENT_B 0x2A -#define ADP5585_RESET1_EVENT_C 0x2B -#define ADP5585_RESET2_EVENT_A 0x2C -#define ADP5585_RESET2_EVENT_B 0x2D -#define ADP5585_RESET_CFG 0x2E -#define ADP5585_PWM_OFFT_LOW 0x2F -#define ADP5585_PWM_OFFT_HIGH 0x30 -#define ADP5585_PWM_ONT_LOW 0x31 -#define ADP5585_PWM_ONT_HIGH 0x32 -#define ADP5585_PWM_CFG 0x33 -#define ADP5585_LOGIC_CFG 0x34 -#define ADP5585_LOGIC_FF_CFG 0x35 -#define ADP5585_LOGIC_INT_EVENT_EN 0x36 -#define ADP5585_POLL_PTIME_CFG 0x37 -#define ADP5585_PIN_CONFIG_A 0x38 -#define ADP5585_PIN_CONFIG_B 0x39 -#define ADP5585_PIN_CONFIG_D 0x3A -#define ADP5585_GENERAL_CFG 0x3B -#define ADP5585_INT_EN 0x3C - -/* ID Register */ -#define ADP5589_5_DEVICE_ID_MASK 0xF -#define ADP5589_5_MAN_ID_MASK 0xF -#define ADP5589_5_MAN_ID_SHIFT 4 -#define ADP5589_5_MAN_ID 0x02 - -/* GENERAL_CFG Register */ -#define OSC_EN BIT(7) -#define CORE_CLK(x) (((x) & 0x3) << 5) -#define LCK_TRK_LOGIC BIT(4) /* ADP5589 only */ -#define LCK_TRK_GPI BIT(3) /* ADP5589 only */ -#define INT_CFG BIT(1) -#define RST_CFG BIT(0) - -/* INT_EN Register */ -#define LOGIC2_IEN BIT(5) /* ADP5589 only */ -#define LOGIC1_IEN BIT(4) -#define LOCK_IEN BIT(3) /* ADP5589 only */ -#define OVRFLOW_IEN BIT(2) -#define GPI_IEN BIT(1) -#define EVENT_IEN BIT(0) - -/* Interrupt Status Register */ -#define LOGIC2_INT BIT(5) /* ADP5589 only */ -#define LOGIC1_INT BIT(4) -#define LOCK_INT BIT(3) /* ADP5589 only */ -#define OVRFLOW_INT BIT(2) -#define GPI_INT BIT(1) -#define EVENT_INT BIT(0) - -/* STATUS Register */ -#define LOGIC2_STAT BIT(7) /* ADP5589 only */ -#define LOGIC1_STAT BIT(6) -#define LOCK_STAT BIT(5) /* ADP5589 only */ -#define KEC 0x1F - -/* PIN_CONFIG_D Register */ -#define C4_EXTEND_CFG BIT(6) /* RESET2 */ -#define R4_EXTEND_CFG BIT(5) /* RESET1 */ - -/* LOCK_CFG */ -#define LOCK_EN BIT(0) - -#define PTIME_MASK 0x3 -#define LTIME_MASK 0x3 /* ADP5589 only */ - -/* Key Event Register xy */ -#define KEY_EV_PRESSED BIT(7) -#define KEY_EV_MASK 0x7F - -#define KEYP_MAX_EVENT 16 -#define ADP5589_MAXGPIO 19 -#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */ - -enum { - ADP5589, - ADP5585_01, - ADP5585_02 -}; - -struct adp_constants { - u8 maxgpio; - u8 keymapsize; - u8 gpi_pin_row_base; - u8 gpi_pin_row_end; - u8 gpi_pin_col_base; - u8 gpi_pin_base; - u8 gpi_pin_end; - u8 gpimapsize_max; - u8 max_row_num; - u8 max_col_num; - u8 row_mask; - u8 col_mask; - u8 col_shift; - u8 c4_extend_cfg; - u8 (*bank) (u8 offset); - u8 (*bit) (u8 offset); - u8 (*reg) (u8 reg); -}; - -struct adp5589_kpad { - struct i2c_client *client; - struct input_dev *input; - const struct adp_constants *var; - unsigned short keycode[ADP5589_KEYMAPSIZE]; - const struct adp5589_gpi_map *gpimap; - unsigned short gpimapsize; - unsigned extend_cfg; - bool is_adp5585; - bool support_row5; -#ifdef CONFIG_GPIOLIB - unsigned char gpiomap[ADP5589_MAXGPIO]; - struct gpio_chip gc; - struct mutex gpio_lock; /* Protect cached dir, dat_out */ - u8 dat_out[3]; - u8 dir[3]; -#endif -}; - -/* - * ADP5589 / ADP5585 derivative / variant handling - */ - - -/* ADP5589 */ - -static unsigned char adp5589_bank(unsigned char offset) -{ - return offset >> 3; -} - -static unsigned char adp5589_bit(unsigned char offset) -{ - return 1u << (offset & 0x7); -} - -static unsigned char adp5589_reg(unsigned char reg) -{ - return reg; -} - -static const struct adp_constants const_adp5589 = { - .maxgpio = ADP5589_MAXGPIO, - .keymapsize = ADP5589_KEYMAPSIZE, - .gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE, - .gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END, - .gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE, - .gpi_pin_base = ADP5589_GPI_PIN_BASE, - .gpi_pin_end = ADP5589_GPI_PIN_END, - .gpimapsize_max = ADP5589_GPIMAPSIZE_MAX, - .c4_extend_cfg = 12, - .max_row_num = ADP5589_MAX_ROW_NUM, - .max_col_num = ADP5589_MAX_COL_NUM, - .row_mask = ADP5589_ROW_MASK, - .col_mask = ADP5589_COL_MASK, - .col_shift = ADP5589_COL_SHIFT, - .bank = adp5589_bank, - .bit = adp5589_bit, - .reg = adp5589_reg, -}; - -/* ADP5585 */ - -static unsigned char adp5585_bank(unsigned char offset) -{ - return offset > ADP5585_MAX_ROW_NUM; -} - -static unsigned char adp5585_bit(unsigned char offset) -{ - return (offset > ADP5585_MAX_ROW_NUM) ? - 1u << (offset - ADP5585_COL_SHIFT) : 1u << offset; -} - -static const unsigned char adp5585_reg_lut[] = { - [ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A, - [ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B, - [ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A, - [ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B, - [ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C, - [ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D, - [ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A, - [ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B, - [ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A, - [ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B, - [ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A, - [ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B, - [ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A, - [ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B, - [ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A, - [ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B, - [ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A, - [ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B, - [ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A, - [ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B, - [ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A, - [ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B, - [ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C, - [ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A, - [ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B, - [ADP5589_RESET_CFG] = ADP5585_RESET_CFG, - [ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW, - [ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH, - [ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW, - [ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH, - [ADP5589_PWM_CFG] = ADP5585_PWM_CFG, - [ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG, - [ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG, - [ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN, - [ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG, - [ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A, - [ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B, - [ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D, - [ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG, - [ADP5589_INT_EN] = ADP5585_INT_EN, -}; - -static unsigned char adp5585_reg(unsigned char reg) -{ - return adp5585_reg_lut[reg]; -} - -static const struct adp_constants const_adp5585 = { - .maxgpio = ADP5585_MAXGPIO, - .keymapsize = ADP5585_KEYMAPSIZE, - .gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE, - .gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END, - .gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE, - .gpi_pin_base = ADP5585_GPI_PIN_BASE, - .gpi_pin_end = ADP5585_GPI_PIN_END, - .gpimapsize_max = ADP5585_GPIMAPSIZE_MAX, - .c4_extend_cfg = 10, - .max_row_num = ADP5585_MAX_ROW_NUM, - .max_col_num = ADP5585_MAX_COL_NUM, - .row_mask = ADP5585_ROW_MASK, - .col_mask = ADP5585_COL_MASK, - .col_shift = ADP5585_COL_SHIFT, - .bank = adp5585_bank, - .bit = adp5585_bit, - .reg = adp5585_reg, -}; - -static int adp5589_read(struct i2c_client *client, u8 reg) -{ - int ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - dev_err(&client->dev, "Read Error\n"); - - return ret; -} - -static int adp5589_write(struct i2c_client *client, u8 reg, u8 val) -{ - return i2c_smbus_write_byte_data(client, reg, val); -} - -#ifdef CONFIG_GPIOLIB -static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off) -{ - struct adp5589_kpad *kpad = gpiochip_get_data(chip); - unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); - unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - int val; - - mutex_lock(&kpad->gpio_lock); - if (kpad->dir[bank] & bit) - val = kpad->dat_out[bank]; - else - val = adp5589_read(kpad->client, - kpad->var->reg(ADP5589_GPI_STATUS_A) + bank); - mutex_unlock(&kpad->gpio_lock); - - return !!(val & bit); -} - -static void adp5589_gpio_set_value(struct gpio_chip *chip, - unsigned off, int val) -{ - struct adp5589_kpad *kpad = gpiochip_get_data(chip); - unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); - unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - - guard(mutex)(&kpad->gpio_lock); - - if (val) - kpad->dat_out[bank] |= bit; - else - kpad->dat_out[bank] &= ~bit; - - adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + - bank, kpad->dat_out[bank]); -} - -static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off) -{ - struct adp5589_kpad *kpad = gpiochip_get_data(chip); - unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); - unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - - guard(mutex)(&kpad->gpio_lock); - - kpad->dir[bank] &= ~bit; - return adp5589_write(kpad->client, - kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, - kpad->dir[bank]); -} - -static int adp5589_gpio_direction_output(struct gpio_chip *chip, - unsigned off, int val) -{ - struct adp5589_kpad *kpad = gpiochip_get_data(chip); - unsigned int bank = kpad->var->bank(kpad->gpiomap[off]); - unsigned int bit = kpad->var->bit(kpad->gpiomap[off]); - int error; - - guard(mutex)(&kpad->gpio_lock); - - kpad->dir[bank] |= bit; - - if (val) - kpad->dat_out[bank] |= bit; - else - kpad->dat_out[bank] &= ~bit; - - error = adp5589_write(kpad->client, - kpad->var->reg(ADP5589_GPO_DATA_OUT_A) + bank, - kpad->dat_out[bank]); - if (error) - return error; - - error = adp5589_write(kpad->client, - kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank, - kpad->dir[bank]); - if (error) - return error; - - return 0; -} - -static int adp5589_build_gpiomap(struct adp5589_kpad *kpad, - const struct adp5589_kpad_platform_data *pdata) -{ - bool pin_used[ADP5589_MAXGPIO]; - int n_unused = 0; - int i; - - memset(pin_used, false, sizeof(pin_used)); - - for (i = 0; i < kpad->var->maxgpio; i++) - if (pdata->keypad_en_mask & BIT(i)) - pin_used[i] = true; - - for (i = 0; i < kpad->gpimapsize; i++) - pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true; - - if (kpad->extend_cfg & R4_EXTEND_CFG) - pin_used[4] = true; - - if (kpad->extend_cfg & C4_EXTEND_CFG) - pin_used[kpad->var->c4_extend_cfg] = true; - - if (!kpad->support_row5) - pin_used[5] = true; - - for (i = 0; i < kpad->var->maxgpio; i++) - if (!pin_used[i]) - kpad->gpiomap[n_unused++] = i; - - return n_unused; -} - -static int adp5589_gpio_add(struct adp5589_kpad *kpad) -{ - struct device *dev = &kpad->client->dev; - const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev); - const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data; - int i, error; - - if (!gpio_data) - return 0; - - kpad->gc.parent = dev; - kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata); - if (kpad->gc.ngpio == 0) { - dev_info(dev, "No unused gpios left to export\n"); - return 0; - } - - kpad->gc.direction_input = adp5589_gpio_direction_input; - kpad->gc.direction_output = adp5589_gpio_direction_output; - kpad->gc.get = adp5589_gpio_get_value; - kpad->gc.set = adp5589_gpio_set_value; - kpad->gc.can_sleep = 1; - - kpad->gc.base = gpio_data->gpio_start; - kpad->gc.label = kpad->client->name; - kpad->gc.owner = THIS_MODULE; - - mutex_init(&kpad->gpio_lock); - - error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); - if (error) - return error; - - for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) { - kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg( - ADP5589_GPO_DATA_OUT_A) + i); - kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg( - ADP5589_GPIO_DIRECTION_A) + i); - } - - return 0; -} -#else -static inline int adp5589_gpio_add(struct adp5589_kpad *kpad) -{ - return 0; -} -#endif - -static void adp5589_report_switches(struct adp5589_kpad *kpad, - int key, int key_val) -{ - int i; - - for (i = 0; i < kpad->gpimapsize; i++) { - if (key_val == kpad->gpimap[i].pin) { - input_report_switch(kpad->input, - kpad->gpimap[i].sw_evt, - key & KEY_EV_PRESSED); - break; - } - } -} - -static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt) -{ - int i; - - for (i = 0; i < ev_cnt; i++) { - int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i); - int key_val = key & KEY_EV_MASK; - - if (key_val >= kpad->var->gpi_pin_base && - key_val <= kpad->var->gpi_pin_end) { - adp5589_report_switches(kpad, key, key_val); - } else { - input_report_key(kpad->input, - kpad->keycode[key_val - 1], - key & KEY_EV_PRESSED); - } - } -} - -static irqreturn_t adp5589_irq(int irq, void *handle) -{ - struct adp5589_kpad *kpad = handle; - struct i2c_client *client = kpad->client; - int status, ev_cnt; - - status = adp5589_read(client, ADP5589_5_INT_STATUS); - - if (status & OVRFLOW_INT) /* Unlikely and should never happen */ - dev_err(&client->dev, "Event Overflow Error\n"); - - if (status & EVENT_INT) { - ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC; - if (ev_cnt) { - adp5589_report_events(kpad, ev_cnt); - input_sync(kpad->input); - } - } - - adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */ - - return IRQ_HANDLED; -} - -static int adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key) -{ - int i; - - for (i = 0; i < kpad->var->keymapsize; i++) - if (key == kpad->keycode[i]) - return (i + 1) | KEY_EV_PRESSED; - - dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n"); - - return -EINVAL; -} - -static int adp5589_setup(struct adp5589_kpad *kpad) -{ - struct i2c_client *client = kpad->client; - const struct adp5589_kpad_platform_data *pdata = - dev_get_platdata(&client->dev); - u8 (*reg) (u8) = kpad->var->reg; - unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0; - unsigned char pull_mask = 0; - int i, ret; - - ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A), - pdata->keypad_en_mask & kpad->var->row_mask); - ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B), - (pdata->keypad_en_mask >> kpad->var->col_shift) & - kpad->var->col_mask); - - if (!kpad->is_adp5585) - ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C, - (pdata->keypad_en_mask >> 16) & 0xFF); - - if (!kpad->is_adp5585 && pdata->en_keylock) { - ret |= adp5589_write(client, ADP5589_UNLOCK1, - pdata->unlock_key1); - ret |= adp5589_write(client, ADP5589_UNLOCK2, - pdata->unlock_key2); - ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS, - pdata->unlock_timer & LTIME_MASK); - ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN); - } - - for (i = 0; i < KEYP_MAX_EVENT; i++) - ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i); - - for (i = 0; i < pdata->gpimapsize; i++) { - unsigned short pin = pdata->gpimap[i].pin; - - if (pin <= kpad->var->gpi_pin_row_end) { - evt_mode1 |= BIT(pin - kpad->var->gpi_pin_row_base); - } else { - evt_mode2 |= - BIT(pin - kpad->var->gpi_pin_col_base) & 0xFF; - if (!kpad->is_adp5585) - evt_mode3 |= - BIT(pin - kpad->var->gpi_pin_col_base) >> 8; - } - } - - if (pdata->gpimapsize) { - ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A), - evt_mode1); - ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B), - evt_mode2); - if (!kpad->is_adp5585) - ret |= adp5589_write(client, - reg(ADP5589_GPI_EVENT_EN_C), - evt_mode3); - } - - if (pdata->pull_dis_mask & pdata->pullup_en_100k & - pdata->pullup_en_300k & pdata->pulldown_en_300k) - dev_warn(&client->dev, "Conflicting pull resistor config\n"); - - for (i = 0; i <= kpad->var->max_row_num; i++) { - unsigned int val = 0, bit = BIT(i); - if (pdata->pullup_en_300k & bit) - val = 0; - else if (pdata->pulldown_en_300k & bit) - val = 1; - else if (pdata->pullup_en_100k & bit) - val = 2; - else if (pdata->pull_dis_mask & bit) - val = 3; - - pull_mask |= val << (2 * (i & 0x3)); - - if (i % 4 == 3 || i == kpad->var->max_row_num) { - ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A) - + (i >> 2), pull_mask); - pull_mask = 0; - } - } - - for (i = 0; i <= kpad->var->max_col_num; i++) { - unsigned int val = 0, bit = BIT(i + kpad->var->col_shift); - if (pdata->pullup_en_300k & bit) - val = 0; - else if (pdata->pulldown_en_300k & bit) - val = 1; - else if (pdata->pullup_en_100k & bit) - val = 2; - else if (pdata->pull_dis_mask & bit) - val = 3; - - pull_mask |= val << (2 * (i & 0x3)); - - if (i % 4 == 3 || i == kpad->var->max_col_num) { - ret |= adp5589_write(client, - reg(ADP5585_RPULL_CONFIG_C) + - (i >> 2), pull_mask); - pull_mask = 0; - } - } - - if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) { - ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A), - adp5589_get_evcode(kpad, - pdata->reset1_key_1)); - ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B), - adp5589_get_evcode(kpad, - pdata->reset1_key_2)); - ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C), - adp5589_get_evcode(kpad, - pdata->reset1_key_3)); - kpad->extend_cfg |= R4_EXTEND_CFG; - } - - if (pdata->reset2_key_1 && pdata->reset2_key_2) { - ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A), - adp5589_get_evcode(kpad, - pdata->reset2_key_1)); - ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B), - adp5589_get_evcode(kpad, - pdata->reset2_key_2)); - kpad->extend_cfg |= C4_EXTEND_CFG; - } - - if (kpad->extend_cfg) { - ret |= adp5589_write(client, reg(ADP5589_RESET_CFG), - pdata->reset_cfg); - ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D), - kpad->extend_cfg); - } - - ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A), - pdata->debounce_dis_mask & kpad->var->row_mask); - - ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B), - (pdata->debounce_dis_mask >> kpad->var->col_shift) - & kpad->var->col_mask); - - if (!kpad->is_adp5585) - ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C), - (pdata->debounce_dis_mask >> 16) & 0xFF); - - ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG), - pdata->scan_cycle_time & PTIME_MASK); - ret |= adp5589_write(client, ADP5589_5_INT_STATUS, - (kpad->is_adp5585 ? 0 : LOGIC2_INT) | - LOGIC1_INT | OVRFLOW_INT | - (kpad->is_adp5585 ? 0 : LOCK_INT) | - GPI_INT | EVENT_INT); /* Status is W1C */ - - ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG), - INT_CFG | OSC_EN | CORE_CLK(3)); - ret |= adp5589_write(client, reg(ADP5589_INT_EN), - OVRFLOW_IEN | GPI_IEN | EVENT_IEN); - - if (ret < 0) { - dev_err(&client->dev, "Write Error\n"); - return ret; - } - - return 0; -} - -static void adp5589_report_switch_state(struct adp5589_kpad *kpad) -{ - int gpi_stat_tmp, pin_loc; - int i; - int gpi_stat1 = adp5589_read(kpad->client, - kpad->var->reg(ADP5589_GPI_STATUS_A)); - int gpi_stat2 = adp5589_read(kpad->client, - kpad->var->reg(ADP5589_GPI_STATUS_B)); - int gpi_stat3 = !kpad->is_adp5585 ? - adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0; - - for (i = 0; i < kpad->gpimapsize; i++) { - unsigned short pin = kpad->gpimap[i].pin; - - if (pin <= kpad->var->gpi_pin_row_end) { - gpi_stat_tmp = gpi_stat1; - pin_loc = pin - kpad->var->gpi_pin_row_base; - } else if ((pin - kpad->var->gpi_pin_col_base) < 8) { - gpi_stat_tmp = gpi_stat2; - pin_loc = pin - kpad->var->gpi_pin_col_base; - } else { - gpi_stat_tmp = gpi_stat3; - pin_loc = pin - kpad->var->gpi_pin_col_base - 8; - } - - if (gpi_stat_tmp < 0) { - dev_err(&kpad->client->dev, - "Can't read GPIO_DAT_STAT switch %d, default to OFF\n", - pin); - gpi_stat_tmp = 0; - } - - input_report_switch(kpad->input, - kpad->gpimap[i].sw_evt, - !(gpi_stat_tmp & BIT(pin_loc))); - } - - input_sync(kpad->input); -} - -static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) -{ - struct i2c_client *client = kpad->client; - const struct adp5589_kpad_platform_data *pdata = - dev_get_platdata(&client->dev); - struct input_dev *input; - unsigned int i; - int error; - - if (!((pdata->keypad_en_mask & kpad->var->row_mask) && - (pdata->keypad_en_mask >> kpad->var->col_shift)) || - !pdata->keymap) { - dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); - return -EINVAL; - } - - if (pdata->keymapsize != kpad->var->keymapsize) { - dev_err(&client->dev, "invalid keymapsize\n"); - return -EINVAL; - } - - if (!pdata->gpimap && pdata->gpimapsize) { - dev_err(&client->dev, "invalid gpimap from pdata\n"); - return -EINVAL; - } - - if (pdata->gpimapsize > kpad->var->gpimapsize_max) { - dev_err(&client->dev, "invalid gpimapsize\n"); - return -EINVAL; - } - - for (i = 0; i < pdata->gpimapsize; i++) { - unsigned short pin = pdata->gpimap[i].pin; - - if (pin < kpad->var->gpi_pin_base || - pin > kpad->var->gpi_pin_end) { - dev_err(&client->dev, "invalid gpi pin data\n"); - return -EINVAL; - } - - if (BIT(pin - kpad->var->gpi_pin_row_base) & - pdata->keypad_en_mask) { - dev_err(&client->dev, "invalid gpi row/col data\n"); - return -EINVAL; - } - } - - if (!client->irq) { - dev_err(&client->dev, "no IRQ?\n"); - return -EINVAL; - } - - input = devm_input_allocate_device(&client->dev); - if (!input) - return -ENOMEM; - - kpad->input = input; - - input->name = client->name; - input->phys = "adp5589-keys/input0"; - input->dev.parent = &client->dev; - - input_set_drvdata(input, kpad); - - input->id.bustype = BUS_I2C; - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = revid; - - input->keycodesize = sizeof(kpad->keycode[0]); - input->keycodemax = pdata->keymapsize; - input->keycode = kpad->keycode; - - memcpy(kpad->keycode, pdata->keymap, - pdata->keymapsize * input->keycodesize); - - kpad->gpimap = pdata->gpimap; - kpad->gpimapsize = pdata->gpimapsize; - - /* setup input device */ - __set_bit(EV_KEY, input->evbit); - - if (pdata->repeat) - __set_bit(EV_REP, input->evbit); - - for (i = 0; i < input->keycodemax; i++) - if (kpad->keycode[i] <= KEY_MAX) - __set_bit(kpad->keycode[i], input->keybit); - __clear_bit(KEY_RESERVED, input->keybit); - - if (kpad->gpimapsize) - __set_bit(EV_SW, input->evbit); - for (i = 0; i < kpad->gpimapsize; i++) - __set_bit(kpad->gpimap[i].sw_evt, input->swbit); - - error = input_register_device(input); - if (error) { - dev_err(&client->dev, "unable to register input device\n"); - return error; - } - - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, adp5589_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - client->dev.driver->name, kpad); - if (error) { - dev_err(&client->dev, "unable to request irq %d\n", client->irq); - return error; - } - - return 0; -} - -static void adp5589_clear_config(void *data) -{ - struct adp5589_kpad *kpad = data; - - adp5589_write(kpad->client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); -} - -static int adp5589_probe(struct i2c_client *client) -{ - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct adp5589_kpad *kpad; - const struct adp5589_kpad_platform_data *pdata = - dev_get_platdata(&client->dev); - unsigned int revid; - int error, ret; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); - return -EIO; - } - - if (!pdata) { - dev_err(&client->dev, "no platform data?\n"); - return -EINVAL; - } - - kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL); - if (!kpad) - return -ENOMEM; - - kpad->client = client; - - switch (id->driver_data) { - case ADP5585_02: - kpad->support_row5 = true; - fallthrough; - case ADP5585_01: - kpad->is_adp5585 = true; - kpad->var = &const_adp5585; - break; - case ADP5589: - kpad->support_row5 = true; - kpad->var = &const_adp5589; - break; - } - - error = devm_add_action_or_reset(&client->dev, adp5589_clear_config, - kpad); - if (error) - return error; - - ret = adp5589_read(client, ADP5589_5_ID); - if (ret < 0) - return ret; - - revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; - - if (pdata->keymapsize) { - error = adp5589_keypad_add(kpad, revid); - if (error) - return error; - } - - error = adp5589_setup(kpad); - if (error) - return error; - - if (kpad->gpimapsize) - adp5589_report_switch_state(kpad); - - error = adp5589_gpio_add(kpad); - if (error) - return error; - - dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); - return 0; -} - -static int adp5589_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adp5589_kpad *kpad = i2c_get_clientdata(client); - - if (kpad->input) - disable_irq(client->irq); - - return 0; -} - -static int adp5589_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct adp5589_kpad *kpad = i2c_get_clientdata(client); - - if (kpad->input) - enable_irq(client->irq); - - return 0; -} - -static DEFINE_SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume); - -static const struct i2c_device_id adp5589_id[] = { - {"adp5589-keys", ADP5589}, - {"adp5585-keys", ADP5585_01}, - {"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */ - {} -}; - -MODULE_DEVICE_TABLE(i2c, adp5589_id); - -static struct i2c_driver adp5589_driver = { - .driver = { - .name = KBUILD_MODNAME, - .pm = pm_sleep_ptr(&adp5589_dev_pm_ops), - }, - .probe = adp5589_probe, - .id_table = adp5589_id, -}; - -module_i2c_driver(adp5589_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver"); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index adf0f311996c..8cb4dc6fb165 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -3,10 +3,7 @@ * AT and PS/2 keyboard driver * * Copyright (c) 1999-2002 Vojtech Pavlik - */ - - -/* + * * This driver can handle standard AT keyboards and PS/2 keyboards in * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb * input-only controllers and AT keyboards connected over a one way RS232 @@ -37,7 +34,7 @@ static int atkbd_set = 2; module_param_named(set, atkbd_set, int, 0); MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); -#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) +#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) || defined(__loongarch__) static bool atkbd_reset; #else static bool atkbd_reset = true; @@ -65,8 +62,8 @@ 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 SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) -#define KEYCODE(keymap) (keymap & 0xFFFF) +#define SCANCODE(keymap) (((keymap) >> 16) & 0xFFFF) +#define KEYCODE(keymap) ((keymap) & 0xFFFF) /* * Scancode to keycode tables. These are just the default setting, and @@ -76,7 +73,6 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne #define ATKBD_KEYMAP_SIZE 512 static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { - #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES /* XXX: need a more general approach */ @@ -84,12 +80,12 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { #include "hpps2atkbd.h" /* include the keyboard scancodes */ #else - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 0, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0, 85, + 0, 67, 65, 63, 61, 59, 60, 88,183, 68, 66, 64, 62, 15, 41,117, + 184, 56, 42, 93, 29, 16, 2, 0,185, 0, 44, 31, 30, 17, 3, 0, + 186, 46, 45, 32, 18, 5, 4, 95,187, 57, 47, 33, 20, 19, 6,183, + 188, 49, 48, 35, 34, 21, 7,184,189, 0, 50, 36, 22, 8, 9,185, + 190, 51, 37, 23, 24, 11, 10, 0,191, 52, 53, 38, 39, 25, 12, 0, + 192, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0,194, 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, @@ -107,7 +103,6 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { }; static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, @@ -122,15 +117,15 @@ static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { 148,149,147,140 }; -static const unsigned short atkbd_unxlate_table[128] = { - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 +static const u8 atkbd_unxlate_table[128] = { + 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, + 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, + 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, + 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, + 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, + 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, + 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, + 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 }; #define ATKBD_CMD_SETLEDS 0x10ed @@ -184,7 +179,7 @@ static const unsigned short atkbd_unxlate_table[128] = { static const struct { unsigned short keycode; - unsigned char set2; + u8 set2; } atkbd_scroll_keys[] = { { ATKBD_SCR_1, 0xc5 }, { ATKBD_SCR_2, 0x9d }, @@ -200,7 +195,6 @@ static const struct { */ struct atkbd { - struct ps2dev ps2dev; struct input_dev *dev; @@ -211,7 +205,7 @@ struct atkbd { unsigned short id; unsigned short keycode[ATKBD_KEYMAP_SIZE]; DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); - unsigned char set; + u8 set; bool translated; bool extra; bool write; @@ -221,7 +215,7 @@ struct atkbd { bool enabled; /* Accessed only from interrupt */ - unsigned char emul; + u8 emul; bool resend; bool release; unsigned long xl_bit; @@ -253,9 +247,9 @@ static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned in static bool atkbd_skip_deactivate; static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)); + ssize_t (*handler)(struct atkbd *, char *)); static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)); + ssize_t (*handler)(struct atkbd *, const char *, size_t)); #define ATKBD_DEFINE_ATTR(_name) \ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ @@ -270,7 +264,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, \ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ } \ static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); + __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name) ATKBD_DEFINE_ATTR(extra); ATKBD_DEFINE_ATTR(force_release); @@ -287,7 +281,7 @@ static ssize_t atkbd_do_show_##_name(struct device *d, \ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ } \ static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); + __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL) ATKBD_DEFINE_RO_ATTR(err_count); ATKBD_DEFINE_RO_ATTR(function_row_physmap); @@ -317,7 +311,7 @@ static struct atkbd *atkbd_from_serio(struct serio *serio) } static umode_t atkbd_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) + struct attribute *attr, int i) { struct device *dev = kobj_to_dev(kobj); struct serio *serio = to_serio_port(dev); @@ -337,7 +331,7 @@ static const struct attribute_group atkbd_attribute_group = { __ATTRIBUTE_GROUPS(atkbd_attribute); -static const unsigned int xl_table[] = { +static const u8 xl_table[] = { ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, }; @@ -346,7 +340,7 @@ static const unsigned int xl_table[] = { * Checks if we should mangle the scancode to extract 'release' bit * in translated mode. */ -static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) +static bool atkbd_need_xlate(unsigned long xl_bit, u8 code) { int i; @@ -365,7 +359,7 @@ static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) * between make/break pair of scancodes for select keys and PS/2 * protocol responses. */ -static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) +static void atkbd_calculate_xl_bit(struct atkbd *atkbd, u8 code) { int i; @@ -389,7 +383,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code if (atkbd->set == 3) { if (atkbd->emul == 1) code |= 0x100; - } else { + } else { code = (code & 0x7f) | ((code & 0x80) << 1); if (atkbd->emul == 1) code |= 0x80; @@ -431,7 +425,7 @@ static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev, dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); -#if !defined(__i386__) && !defined (__x86_64__) +#if !defined(__i386__) && !defined(__x86_64__) if (atkbd_handle_frame_error(ps2dev, data, flags)) return PS2_IGNORE; #endif @@ -460,7 +454,6 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) code = atkbd_platform_scancode_fixup(atkbd, code); if (atkbd->translated) { - if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { atkbd->release = code >> 7; code &= 0x7f; @@ -486,11 +479,9 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) return; case ATKBD_RET_ACK: case ATKBD_RET_NAK: - if (printk_ratelimit()) - dev_warn(&serio->dev, - "Spurious %s on %s. " - "Some program might be trying to access hardware directly.\n", - data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); + dev_warn_ratelimited(&serio->dev, + "Spurious %s on %s. Some program might be trying to access hardware directly.\n", + data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); return; case ATKBD_RET_ERR: atkbd->err_count++; @@ -582,14 +573,14 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) static int atkbd_set_repeat_rate(struct atkbd *atkbd) { - const short period[32] = - { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, - 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; - const short delay[4] = - { 250, 500, 750, 1000 }; + const short period[32] = { + 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, + 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 + }; + const short delay[4] = { 250, 500, 750, 1000 }; struct input_dev *dev = atkbd->dev; - unsigned char param; + u8 param; int i = 0, j = 0; while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) @@ -607,7 +598,7 @@ static int atkbd_set_repeat_rate(struct atkbd *atkbd) static int atkbd_set_leds(struct atkbd *atkbd) { struct input_dev *dev = atkbd->dev; - unsigned char param[2]; + u8 param[2]; param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0) @@ -648,8 +639,7 @@ static void atkbd_event_work(struct work_struct *work) * it may not be ready yet. In this case we need to keep * rescheduling till reconnect completes. */ - schedule_delayed_work(&atkbd->event_work, - msecs_to_jiffies(100)); + schedule_delayed_work(&atkbd->event_work, msecs_to_jiffies(100)); } else { if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) atkbd_set_leds(atkbd); @@ -683,7 +673,7 @@ static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit) */ static int atkbd_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { struct atkbd *atkbd = input_get_drvdata(dev); @@ -691,7 +681,6 @@ static int atkbd_event(struct input_dev *dev, return -1; switch (type) { - case EV_LED: atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); return 0; @@ -808,7 +797,7 @@ static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; } static int atkbd_probe(struct atkbd *atkbd) { struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; + u8 param[2]; /* * Some systems, where the bit-twiddling when testing the io-lines of the @@ -836,7 +825,6 @@ static int atkbd_probe(struct atkbd *atkbd) param[0] = param[1] = 0xa5; /* initialize with invalid values */ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { - /* * If the get ID command failed, we check if we can at least set * the LEDs on the keyboard. This should work on every keyboard out there. @@ -856,8 +844,7 @@ static int atkbd_probe(struct atkbd *atkbd) if (atkbd->id == 0xaca1 && atkbd->translated) { dev_err(&ps2dev->serio->dev, - "NCD terminal keyboards are only supported on non-translating controllers. " - "Use i8042.direct=1 to disable translation.\n"); + "NCD terminal keyboards are only supported on non-translating controllers. Use i8042.direct=1 to disable translation.\n"); return -1; } @@ -881,7 +868,7 @@ deactivate_kbd: static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) { struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; + u8 param[2]; atkbd->extra = false; /* @@ -941,8 +928,8 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra static int atkbd_reset_state(struct atkbd *atkbd) { - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[1]; + struct ps2dev *ps2dev = &atkbd->ps2dev; + u8 param[1]; /* * Set the LEDs to a predefined state (all off). @@ -967,7 +954,6 @@ static int atkbd_reset_state(struct atkbd *atkbd) * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a * reboot. */ - static void atkbd_cleanup(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -976,11 +962,9 @@ static void atkbd_cleanup(struct serio *serio) ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); } - /* * atkbd_disconnect() closes and frees. */ - static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1005,8 +989,7 @@ static void atkbd_disconnect(struct serio *serio) /* * generate release events for the keycodes given in data */ -static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, - const void *data) +static void atkbd_apply_forced_release_keylist(struct atkbd *atkbd, const void *data) { const unsigned int *keys = data; unsigned int i; @@ -1088,7 +1071,6 @@ 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 */ @@ -1096,13 +1078,12 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) if (n <= 0 || n > ATKBD_KEYMAP_SIZE) return -ENXIO; - ptr = kcalloc(n, sizeof(u32), GFP_KERNEL); + u32 *ptr __free(kfree) = kcalloc(n, sizeof(*ptr), 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; } @@ -1110,10 +1091,14 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) for (i = 0; i < n; i++) { scancode = SCANCODE(ptr[i]); keycode = KEYCODE(ptr[i]); + if (scancode >= ATKBD_KEYMAP_SIZE) { + dev_warn(dev, "invalid scancode %#x in FW keymap entry %d\n", + scancode, i); + return -EINVAL; + } atkbd->keycode[scancode] = keycode; } - kfree(ptr); return 0; } @@ -1191,8 +1176,8 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) "AT %s Set %d keyboard", atkbd->translated ? "Translated" : "Raw", atkbd->set); - snprintf(atkbd->phys, sizeof(atkbd->phys), - "%s/input0", atkbd->ps2dev.serio->phys); + scnprintf(atkbd->phys, sizeof(atkbd->phys), + "%s/input0", atkbd->ps2dev.serio->phys); input_dev->name = atkbd->name; input_dev->phys = atkbd->phys; @@ -1235,7 +1220,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) } input_dev->keycode = atkbd->keycode; - input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodesize = sizeof(atkbd->keycode[0]); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) { @@ -1277,7 +1262,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *dev; int err = -ENOMEM; - atkbd = kzalloc(sizeof(*atkbd), GFP_KERNEL); + atkbd = kzalloc_obj(*atkbd); dev = input_allocate_device(); if (!atkbd || !dev) goto fail1; @@ -1289,7 +1274,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) mutex_init(&atkbd->mutex); switch (serio->id.type) { - case SERIO_8042_XL: atkbd->translated = true; fallthrough; @@ -1314,7 +1298,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) goto fail2; if (atkbd->write) { - if (atkbd_probe(atkbd)) { err = -ENODEV; goto fail3; @@ -1354,7 +1337,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) * atkbd_reconnect() tries to restore keyboard into a sane state and is * most likely called on resume. */ - static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1389,7 +1371,6 @@ static int atkbd_reconnect(struct serio *serio) atkbd_set_leds(atkbd); if (!atkbd->softrepeat) atkbd_set_repeat_rate(atkbd); - } /* @@ -1445,7 +1426,7 @@ static struct serio_driver atkbd_drv = { }; static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)) + ssize_t (*handler)(struct atkbd *, char *)) { struct serio *serio = to_serio_port(dev); struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1454,7 +1435,7 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, } static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)) + ssize_t (*handler)(struct atkbd *, const char *, size_t)) { struct serio *serio = to_serio_port(dev); struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1482,7 +1463,7 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun unsigned int value; int err; bool old_extra; - unsigned char old_set; + u8 old_set; if (!atkbd->write) return -EIO; @@ -1527,8 +1508,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return err; } input_unregister_device(old_dev); - } + return count; } @@ -1544,7 +1525,7 @@ static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) } static ssize_t atkbd_set_force_release(struct atkbd *atkbd, - const char *buf, size_t count) + const char *buf, size_t count) { /* 64 bytes on stack should be acceptable */ DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); @@ -1558,7 +1539,6 @@ static ssize_t atkbd_set_force_release(struct atkbd *atkbd, return count; } - static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); @@ -1617,7 +1597,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) struct input_dev *old_dev, *new_dev; unsigned int value; int err; - unsigned char old_set; + u8 old_set; bool old_extra; if (!atkbd->write) @@ -1715,7 +1695,6 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t return count; } - static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); @@ -1937,6 +1916,28 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { }, .callback = atkbd_deactivate_fixup, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "FMB-P"), + }, + .callback = atkbd_deactivate_fixup, + }, + { + /* Lenovo Yoga Air 14 (83QK) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83QK"), + }, + .callback = atkbd_deactivate_fixup, + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "BCC-N"), + }, + .callback = atkbd_deactivate_fixup, + }, { } }; diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c new file mode 100644 index 000000000000..6dbb5c183f02 --- /dev/null +++ b/drivers/input/keyboard/charlieplex_keypad.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GPIO driven charlieplex keypad driver + * + * Copyright (c) 2026 Hugo Villeneuve <hvilleneuve@dimonoff.com> + * + * Based on matrix_keyboard.c + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/string_helpers.h> +#include <linux/types.h> + +struct charlieplex_keypad { + struct input_dev *input_dev; + struct gpio_descs *line_gpios; + unsigned int nlines; + unsigned int settling_time_us; + unsigned int debounce_threshold; + unsigned int debounce_count; + int debounce_code; + int current_code; +}; + +static void charlieplex_keypad_report_key(struct input_dev *input) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + const unsigned short *keycodes = input->keycode; + + if (keypad->current_code > 0) { + input_event(input, EV_MSC, MSC_SCAN, keypad->current_code); + input_report_key(input, keycodes[keypad->current_code], 0); + input_sync(input); + } + + if (keypad->debounce_code) { + input_event(input, EV_MSC, MSC_SCAN, keypad->debounce_code); + input_report_key(input, keycodes[keypad->debounce_code], 1); + input_sync(input); + } + + keypad->current_code = keypad->debounce_code; +} + +static void charlieplex_keypad_check_switch_change(struct input_dev *input, + unsigned int code) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + + if (code != keypad->debounce_code) { + keypad->debounce_count = 0; + keypad->debounce_code = code; + } + + if (keypad->debounce_code != keypad->current_code) { + if (keypad->debounce_count++ >= keypad->debounce_threshold) + charlieplex_keypad_report_key(input); + } +} + +static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad, + unsigned int oline) +{ + struct gpio_descs *line_gpios = keypad->line_gpios; + DECLARE_BITMAP(values, MATRIX_MAX_ROWS); + int err; + + /* Activate only one line as output at a time. */ + gpiod_direction_output(line_gpios->desc[oline], 1); + + if (keypad->settling_time_us) + fsleep(keypad->settling_time_us); + + /* Read input on all other lines. */ + err = gpiod_get_array_value_cansleep(line_gpios->ndescs, line_gpios->desc, + line_gpios->info, values); + + gpiod_direction_input(line_gpios->desc[oline]); + + if (err) + return err; + + for (unsigned int iline = 0; iline < keypad->nlines; iline++) { + if (iline == oline) + continue; /* Do not read active output line. */ + + /* Check if GPIO is asserted. */ + if (test_bit(iline, values)) + return MATRIX_SCAN_CODE(oline, iline, + get_count_order(keypad->nlines)); + } + + return 0; +} + +static void charlieplex_keypad_poll(struct input_dev *input) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + int code = 0; + + for (unsigned int oline = 0; oline < keypad->nlines; oline++) { + code = charlieplex_keypad_scan_line(keypad, oline); + if (code != 0) + break; + } + + if (code >= 0) + charlieplex_keypad_check_switch_change(input, code); +} + +static int charlieplex_keypad_init_gpio(struct platform_device *pdev, + struct charlieplex_keypad *keypad) +{ + char **pin_names; + char label[32]; + + snprintf(label, sizeof(label), "%s-pin", pdev->name); + + keypad->line_gpios = devm_gpiod_get_array(&pdev->dev, "line", GPIOD_IN); + if (IS_ERR(keypad->line_gpios)) + return PTR_ERR(keypad->line_gpios); + + keypad->nlines = keypad->line_gpios->ndescs; + + if (keypad->nlines > MATRIX_MAX_ROWS) + return -EINVAL; + + pin_names = devm_kasprintf_strarray(&pdev->dev, label, keypad->nlines); + if (IS_ERR(pin_names)) + return PTR_ERR(pin_names); + + for (unsigned int i = 0; i < keypad->line_gpios->ndescs; i++) + gpiod_set_consumer_name(keypad->line_gpios->desc[i], pin_names[i]); + + return 0; +} + +static int charlieplex_keypad_probe(struct platform_device *pdev) +{ + struct charlieplex_keypad *keypad; + struct input_dev *input_dev; + unsigned int debounce_interval_ms = 5; + unsigned int poll_interval_ms; + int err; + + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + keypad->input_dev = input_dev; + + err = device_property_read_u32(&pdev->dev, "poll-interval", &poll_interval_ms); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to parse 'poll-interval' property\n"); + + if (poll_interval_ms == 0) + return dev_err_probe(&pdev->dev, -EINVAL, "invalid 'poll-interval' value\n"); + + device_property_read_u32(&pdev->dev, "debounce-delay-ms", &debounce_interval_ms); + device_property_read_u32(&pdev->dev, "settling-time-us", &keypad->settling_time_us); + + keypad->current_code = -1; + keypad->debounce_code = -1; + keypad->debounce_threshold = DIV_ROUND_UP(debounce_interval_ms, poll_interval_ms); + + err = charlieplex_keypad_init_gpio(pdev, keypad); + if (err) + return err; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + + err = matrix_keypad_build_keymap(NULL, NULL, keypad->nlines, + keypad->nlines, NULL, input_dev); + if (err) + return dev_err_probe(&pdev->dev, err, "failed to build keymap\n"); + + if (device_property_read_bool(&pdev->dev, "autorepeat")) + __set_bit(EV_REP, input_dev->evbit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + err = input_setup_polling(input_dev, charlieplex_keypad_poll); + if (err) + return dev_err_probe(&pdev->dev, err, "unable to set up polling\n"); + + input_set_poll_interval(input_dev, poll_interval_ms); + + input_set_drvdata(input_dev, keypad); + + err = input_register_device(keypad->input_dev); + if (err) + return err; + + return 0; +} + +static const struct of_device_id charlieplex_keypad_dt_match[] = { + { .compatible = "gpio-charlieplex-keypad" }, + { } +}; +MODULE_DEVICE_TABLE(of, charlieplex_keypad_dt_match); + +static struct platform_driver charlieplex_keypad_driver = { + .probe = charlieplex_keypad_probe, + .driver = { + .name = "charlieplex-keypad", + .of_match_table = charlieplex_keypad_dt_match, + }, +}; +module_platform_driver(charlieplex_keypad_driver); + +MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>"); +MODULE_DESCRIPTION("GPIO driven charlieplex keypad driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index c1e53d87c8a7..177e5d4a3382 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -29,6 +29,12 @@ #include <linux/unaligned.h> +/* + * Maximum size of the normal key matrix, this is limited by the host command + * key_matrix field defined in ec_response_get_next_data_v3 + */ +#define CROS_EC_KEYBOARD_COLS_MAX 18 + /** * struct cros_ec_keyb - Structure representing EC keyboard device * @@ -44,14 +50,17 @@ * @bs_idev: The input device for non-matrix buttons and switches (or NULL). * @notifier: interrupt event notifier for transport devices * @vdata: vivaldi function row data + * @has_fn_map: whether the driver uses an fn function-map layer + * @fn_active: tracks whether the function key is currently pressed + * @fn_combo_active: tracks whether another key was pressed while fn is active */ struct cros_ec_keyb { unsigned int rows; unsigned int cols; int row_shift; bool ghost_filter; - uint8_t *valid_keys; - uint8_t *old_kb_state; + u8 valid_keys[CROS_EC_KEYBOARD_COLS_MAX]; + u8 old_kb_state[CROS_EC_KEYBOARD_COLS_MAX]; struct device *dev; struct cros_ec_device *ec; @@ -61,6 +70,10 @@ struct cros_ec_keyb { struct notifier_block notifier; struct vivaldi_data vdata; + + bool has_fn_map; + bool fn_active; + bool fn_combo_active; }; /** @@ -132,11 +145,11 @@ static const struct cros_ec_bs_map cros_ec_keyb_bs[] = { * Returns true when there is at least one combination of pressed keys that * results in ghosting. */ -static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) +static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, u8 *buf) { int col1, col2, buf1, buf2; struct device *dev = ckdev->dev; - uint8_t *valid_keys = ckdev->valid_keys; + u8 *valid_keys = ckdev->valid_keys; /* * Ghosting happens if for any pressed key X there are other keys @@ -166,20 +179,108 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) return false; } +static void cros_ec_emit_fn_key(struct input_dev *input, unsigned int pos) +{ + input_event(input, EV_MSC, MSC_SCAN, pos); + input_report_key(input, KEY_FN, true); + input_sync(input); + + input_event(input, EV_MSC, MSC_SCAN, pos); + input_report_key(input, KEY_FN, false); +} + +static void cros_ec_keyb_process_key_plain(struct cros_ec_keyb *ckdev, + int row, int col, bool state) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = idev->keycode; + int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + + input_event(idev, EV_MSC, MSC_SCAN, pos); + input_report_key(idev, keycodes[pos], state); +} + +static void cros_ec_keyb_process_key_fn_map(struct cros_ec_keyb *ckdev, + int row, int col, bool state) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = idev->keycode; + unsigned int pos, fn_pos; + unsigned int code, fn_code; + + pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + code = keycodes[pos]; + + if (code == KEY_FN) { + ckdev->fn_active = state; + if (state) { + ckdev->fn_combo_active = false; + } else if (!ckdev->fn_combo_active) { + /* + * Send both Fn press and release events if nothing + * else has been pressed together with Fn. + */ + cros_ec_emit_fn_key(idev, pos); + } + return; + } + + fn_pos = MATRIX_SCAN_CODE(row + ckdev->rows, col, ckdev->row_shift); + fn_code = keycodes[fn_pos]; + + if (state) { + if (ckdev->fn_active) { + ckdev->fn_combo_active = true; + if (!fn_code) + return; /* Discard if no Fn mapping exists */ + + pos = fn_pos; + code = fn_code; + } + } else { + /* + * If the Fn-remapped code is currently pressed, release it. + * Otherwise, release the standard code (if it was pressed). + */ + if (fn_code && test_bit(fn_code, idev->key)) { + pos = fn_pos; + code = fn_code; + } else if (!test_bit(code, idev->key)) { + return; /* Discard, key press code was not sent */ + } + } + + input_event(idev, EV_MSC, MSC_SCAN, pos); + input_report_key(idev, code, state); +} + +static void cros_ec_keyb_process_col(struct cros_ec_keyb *ckdev, int col, + u8 col_state, u8 changed) +{ + for (int row = 0; row < ckdev->rows; row++) { + if (changed & BIT(row)) { + u8 key_state = col_state & BIT(row); + + dev_dbg(ckdev->dev, "changed: [r%d c%d]: byte %02x\n", + row, col, key_state); + + if (ckdev->has_fn_map) + cros_ec_keyb_process_key_fn_map(ckdev, row, col, + key_state); + else + cros_ec_keyb_process_key_plain(ckdev, row, col, + key_state); + } + } +} /* * Compares the new keyboard state to the old one and produces key - * press/release events accordingly. The keyboard state is 13 bytes (one byte - * per column) + * press/release events accordingly. The keyboard state is one byte + * per column. */ -static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, - uint8_t *kb_state, int len) +static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, u8 *kb_state, int len) { - struct input_dev *idev = ckdev->idev; - int col, row; - int new_state; - int old_state; - if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { /* * Simple-minded solution: ignore this state. The obvious @@ -190,25 +291,15 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, return; } - for (col = 0; col < ckdev->cols; col++) { - for (row = 0; row < ckdev->rows; row++) { - int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); - const unsigned short *keycodes = idev->keycode; - - new_state = kb_state[col] & (1 << row); - old_state = ckdev->old_kb_state[col] & (1 << row); - if (new_state != old_state) { - dev_dbg(ckdev->dev, - "changed: [r%d c%d]: byte %02x\n", - row, col, new_state); - - input_event(idev, EV_MSC, MSC_SCAN, pos); - input_report_key(idev, keycodes[pos], - new_state); - } - } - ckdev->old_kb_state[col] = kb_state[col]; + for (int col = 0; col < ckdev->cols; col++) { + u8 changed = kb_state[col] ^ ckdev->old_kb_state[col]; + + if (changed) + cros_ec_keyb_process_col(ckdev, col, kb_state[col], + changed); } + + memcpy(ckdev->old_kb_state, kb_state, sizeof(ckdev->old_kb_state)); input_sync(ckdev->idev); } @@ -246,8 +337,10 @@ static int cros_ec_keyb_work(struct notifier_block *nb, { struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, notifier); - u32 val; + struct ec_response_get_next_event_v3 *event_data; + unsigned int event_size; unsigned int ev_type; + u32 val; /* * If not wake enabled, discard key state changes during @@ -257,25 +350,32 @@ static int cros_ec_keyb_work(struct notifier_block *nb, if (queued_during_suspend && !device_may_wakeup(ckdev->dev)) return NOTIFY_OK; - switch (ckdev->ec->event_data.event_type) { + event_data = &ckdev->ec->event_data; + event_size = ckdev->ec->event_size; + + switch (event_data->event_type) { case EC_MKBP_EVENT_KEY_MATRIX: pm_wakeup_event(ckdev->dev, 0); - if (ckdev->ec->event_size != ckdev->cols) { + if (!ckdev->idev) { + dev_warn_once(ckdev->dev, "Unexpected key matrix event\n"); + return NOTIFY_OK; + } + + if (event_size != ckdev->cols) { dev_err(ckdev->dev, - "Discarded incomplete key matrix event.\n"); + "Discarded key matrix event, unexpected length: %d != %d\n", + ckdev->ec->event_size, ckdev->cols); return NOTIFY_OK; } - cros_ec_keyb_process(ckdev, - ckdev->ec->event_data.data.key_matrix, - ckdev->ec->event_size); + cros_ec_keyb_process(ckdev, event_data->data.key_matrix, event_size); break; case EC_MKBP_EVENT_SYSRQ: pm_wakeup_event(ckdev->dev, 0); - val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq); + val = get_unaligned_le32(&event_data->data.sysrq); dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val); handle_sysrq(val); break; @@ -284,13 +384,11 @@ static int cros_ec_keyb_work(struct notifier_block *nb, case EC_MKBP_EVENT_SWITCH: pm_wakeup_event(ckdev->dev, 0); - if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) { - val = get_unaligned_le32( - &ckdev->ec->event_data.data.buttons); + if (event_data->event_type == EC_MKBP_EVENT_BUTTON) { + val = get_unaligned_le32(&event_data->data.buttons); ev_type = EV_KEY; } else { - val = get_unaligned_le32( - &ckdev->ec->event_data.data.switches); + val = get_unaligned_le32(&event_data->data.switches); ev_type = EV_SW; } cros_ec_keyb_report_bs(ckdev, ev_type, val); @@ -319,8 +417,8 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev) for (col = 0; col < ckdev->cols; col++) { for (row = 0; row < ckdev->rows; row++) { code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)]; - if (code && (code != KEY_BATTERY)) - ckdev->valid_keys[col] |= 1 << row; + if (code != KEY_RESERVED && code != KEY_BATTERY) + ckdev->valid_keys[col] |= BIT(row); } dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n", col, ckdev->valid_keys[col]); @@ -576,6 +674,62 @@ static void cros_ec_keyb_parse_vivaldi_physmap(struct cros_ec_keyb *ckdev) ckdev->vdata.num_function_row_keys = n_physmap; } +/* Returns true if there is a KEY_FN code defined in the normal keymap */ +static bool cros_ec_keyb_has_fn_key(struct cros_ec_keyb *ckdev) +{ + const unsigned short *keycodes = ckdev->idev->keycode; + int i; + + for (i = 0; i < MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); i++) { + if (keycodes[i] == KEY_FN) + return true; + } + + return false; +} + +/* + * Returns true if there is a KEY_FN defined and at least one key in the fn + * layer keymap + */ +static bool cros_ec_keyb_has_fn_map(struct cros_ec_keyb *ckdev) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = ckdev->idev->keycode; + int i; + + if (!cros_ec_keyb_has_fn_key(ckdev)) + return false; + + for (i = MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); + i < idev->keycodemax; i++) { + if (keycodes[i] != KEY_RESERVED) + return true; + } + + return false; +} + +/* + * Custom handler for the set keycode ioctl, calls the default handler and + * recomputes has_fn_map. + */ +static int cros_ec_keyb_setkeycode(struct input_dev *idev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) +{ + struct cros_ec_keyb *ckdev = input_get_drvdata(idev); + int ret; + + ret = input_default_setkeycode(idev, ke, old_keycode); + if (ret) + return ret; + + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); + + return 0; +} + /** * cros_ec_keyb_register_matrix - Register matrix keys * @@ -597,13 +751,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) if (err) return err; - ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); - if (!ckdev->valid_keys) - return -ENOMEM; - - ckdev->old_kb_state = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); - if (!ckdev->old_kb_state) - return -ENOMEM; + if (ckdev->cols > CROS_EC_KEYBOARD_COLS_MAX) { + dev_err(dev, "keypad,num-columns too large: %d (max: %d)\n", + ckdev->cols, CROS_EC_KEYBOARD_COLS_MAX); + return -EINVAL; + } /* * We call the keyboard matrix 'input0'. Allocate phys before input @@ -625,11 +777,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) idev->id.version = 1; idev->id.product = 0; idev->dev.parent = dev; + idev->setkeycode = cros_ec_keyb_setkeycode; - ckdev->ghost_filter = device_property_read_bool(dev, - "google,needs-ghost-filter"); + ckdev->ghost_filter = device_property_read_bool(dev, "google,needs-ghost-filter"); - err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, + err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows * 2, ckdev->cols, NULL, idev); if (err) { dev_err(dev, "cannot build key matrix\n"); @@ -644,6 +796,8 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) cros_ec_keyb_compute_valid_keys(ckdev); cros_ec_keyb_parse_vivaldi_physmap(ckdev); + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); + err = input_register_device(ckdev->idev); if (err) { dev_err(dev, "cannot register input device\n"); @@ -705,6 +859,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) ec = dev_get_drvdata(pdev->dev.parent); if (!ec) return -EPROBE_DEFER; + /* + * Even if the cros_ec_device pointer is available, still need to check + * if the device is fully registered before using it. + */ + if (!cros_ec_device_registered(ec)) + return -EPROBE_DEFER; ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL); if (!ckdev) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 5eef66516e37..e19617485679 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -434,7 +434,7 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) ms_to_ktime(bdata->software_debounce), HRTIMER_MODE_REL); } else { - mod_delayed_work(system_wq, + mod_delayed_work(system_dfl_wq, &bdata->work, msecs_to_jiffies(bdata->software_debounce)); } @@ -449,6 +449,8 @@ static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t) release_timer); struct input_dev *input = bdata->input; + guard(spinlock_irqsave)(&bdata->lock); + if (bdata->key_pressed) { input_report_key(input, *bdata->code, 0); input_sync(input); @@ -486,7 +488,7 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) if (bdata->release_delay) hrtimer_start(&bdata->release_timer, ms_to_ktime(bdata->release_delay), - HRTIMER_MODE_REL_HARD); + HRTIMER_MODE_REL); out: return IRQ_HANDLED; } @@ -590,9 +592,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); - hrtimer_init(&bdata->debounce_timer, - CLOCK_REALTIME, HRTIMER_MODE_REL); - bdata->debounce_timer.function = gpio_keys_debounce_timer; + hrtimer_setup(&bdata->debounce_timer, gpio_keys_debounce_timer, + CLOCK_REALTIME, HRTIMER_MODE_REL); isr = gpio_keys_gpio_isr; irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; @@ -615,12 +616,19 @@ static int gpio_keys_setup_key(struct platform_device *pdev, break; } } else { - if (!button->irq) { - dev_err(dev, "Found button without gpio or irq\n"); - return -EINVAL; - } + if (button->irq) { + bdata->irq = button->irq; + } else { + irq = platform_get_irq_optional(pdev, idx); + if (irq < 0) { + error = irq; + return dev_err_probe(dev, error, + "Unable to determine IRQ# for button #%d", + idx); + } - bdata->irq = button->irq; + bdata->irq = irq; + } if (button->type && button->type != EV_KEY) { dev_err(dev, "Only EV_KEY allowed for IRQ buttons.\n"); @@ -628,9 +636,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev, } bdata->release_delay = button->debounce_interval; - hrtimer_init(&bdata->release_timer, - CLOCK_REALTIME, HRTIMER_MODE_REL_HARD); - bdata->release_timer.function = gpio_keys_irq_timer; + hrtimer_setup(&bdata->release_timer, gpio_keys_irq_timer, + CLOCK_REALTIME, HRTIMER_MODE_REL); isr = gpio_keys_irq_isr; irqflags = 0; diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index 54afb38601b9..5ebde20df755 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -447,7 +447,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv) uint8_t did, *idd; int error; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc_obj(*dev); input_dev = input_allocate_device(); if (!dev || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index b92268ddfd84..ccde60cd6bb3 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -183,7 +183,8 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad, */ static void imx_keypad_check_for_events(struct timer_list *t) { - struct imx_keypad *keypad = from_timer(keypad, t, check_matrix_timer); + struct imx_keypad *keypad = timer_container_of(keypad, t, + check_matrix_timer); unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS]; unsigned short reg_val; bool state_changed, is_zero_matrix; @@ -323,7 +324,7 @@ static void imx_keypad_config(struct imx_keypad *keypad) reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */ writew(reg_val, keypad->mmio_base + KPCR); - /* Write 0's to KPDR[15:8] (Colums) */ + /* Write 0's to KPDR[15:8] (Columns) */ reg_val = readw(keypad->mmio_base + KPDR); reg_val &= 0x00ff; writew(reg_val, keypad->mmio_base + KPDR); @@ -356,7 +357,7 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad) reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD; writew(reg_val, keypad->mmio_base + KPSR); - /* Colums as open drain and disable all rows */ + /* Columns as open drain and disable all rows */ reg_val = (keypad->cols_en_mask & 0xff) << 8; writew(reg_val, keypad->mmio_base + KPCR); } @@ -370,7 +371,7 @@ static void imx_keypad_close(struct input_dev *dev) /* Mark keypad as being inactive */ keypad->enabled = false; synchronize_irq(keypad->irq); - del_timer_sync(&keypad->check_matrix_timer); + timer_delete_sync(&keypad->check_matrix_timer); imx_keypad_inhibit(keypad); diff --git a/drivers/input/keyboard/imx_sc_key.c b/drivers/input/keyboard/imx_sc_key.c index d18839f1f4f6..b620cd310cdb 100644 --- a/drivers/input/keyboard/imx_sc_key.c +++ b/drivers/input/keyboard/imx_sc_key.c @@ -158,7 +158,7 @@ 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); + error = devm_add_action_or_reset(&pdev->dev, imx_sc_key_action, priv); if (error) return error; diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c index 58631bf7ce55..ca7ec054b1ce 100644 --- a/drivers/input/keyboard/ipaq-micro-keys.c +++ b/drivers/input/keyboard/ipaq-micro-keys.c @@ -102,9 +102,8 @@ static int micro_key_probe(struct platform_device *pdev) keys->input->keycodesize = sizeof(micro_keycodes[0]); keys->input->keycodemax = ARRAY_SIZE(micro_keycodes); - keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes, - keys->input->keycodesize * keys->input->keycodemax, - GFP_KERNEL); + keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax, + keys->input->keycodesize, GFP_KERNEL); if (!keys->codes) return -ENOMEM; diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index c035216dd27c..f5c2267a2c00 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -608,7 +608,7 @@ static int lkkbd_connect(struct serio *serio, struct serio_driver *drv) int i; int err; - lk = kzalloc(sizeof(*lk), GFP_KERNEL); + lk = kzalloc_obj(*lk); input_dev = input_allocate_device(); if (!lk || !input_dev) { err = -ENOMEM; @@ -670,7 +670,8 @@ static int lkkbd_connect(struct serio *serio, struct serio_driver *drv) return 0; - fail3: serio_close(serio); + fail3: disable_work_sync(&lk->tq); + serio_close(serio); fail2: serio_set_drvdata(serio, NULL); fail1: input_free_device(input_dev); kfree(lk); @@ -684,6 +685,8 @@ static void lkkbd_disconnect(struct serio *serio) { struct lkkbd *lk = serio_get_drvdata(serio); + disable_work_sync(&lk->tq); + input_get_device(lk->dev); input_unregister_device(lk->dev); serio_close(serio); diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index c501a93a4417..6351562ebf8d 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -194,7 +194,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) */ static void locomokbd_timer_callback(struct timer_list *t) { - struct locomokbd *locomokbd = from_timer(locomokbd, t, timer); + struct locomokbd *locomokbd = timer_container_of(locomokbd, t, timer); locomokbd_scankeyboard(locomokbd); } @@ -224,7 +224,7 @@ static int locomokbd_probe(struct locomo_dev *dev) struct input_dev *input_dev; int i, err; - locomokbd = kzalloc(sizeof(*locomokbd), GFP_KERNEL); + locomokbd = kzalloc_obj(*locomokbd); input_dev = input_allocate_device(); if (!locomokbd || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c index 1a8f1fa53fbb..80a5181313e1 100644 --- a/drivers/input/keyboard/maple_keyb.c +++ b/drivers/input/keyboard/maple_keyb.c @@ -151,7 +151,7 @@ static int probe_maple_kbd(struct device *dev) mdev = to_maple_dev(dev); mdrv = to_maple_driver(dev->driver); - kbd = kzalloc(sizeof(*kbd), GFP_KERNEL); + kbd = kzalloc_obj(*kbd); if (!kbd) { error = -ENOMEM; goto fail; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 2a3b3bfc2878..e50a6fea9a60 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -26,6 +26,7 @@ struct matrix_keypad { unsigned int row_shift; unsigned int col_scan_delay_us; + unsigned int all_cols_on_delay_us; /* key debounce interval in milli-second */ unsigned int debounce_ms; bool drive_inactive_cols; @@ -68,7 +69,7 @@ static void activate_col(struct matrix_keypad *keypad, int col, bool on) __activate_col(keypad, col, on); if (on && keypad->col_scan_delay_us) - udelay(keypad->col_scan_delay_us); + fsleep(keypad->col_scan_delay_us); } static void activate_all_cols(struct matrix_keypad *keypad, bool on) @@ -77,6 +78,9 @@ static void activate_all_cols(struct matrix_keypad *keypad, bool on) for (col = 0; col < keypad->num_col_gpios; col++) __activate_col(keypad, col, on); + + if (on && keypad->all_cols_on_delay_us) + fsleep(keypad->all_cols_on_delay_us); } static bool row_asserted(struct matrix_keypad *keypad, int row) @@ -100,6 +104,16 @@ static void disable_row_irqs(struct matrix_keypad *keypad) disable_irq_nosync(keypad->row_irqs[i]); } +static uint32_t read_row_state(struct matrix_keypad *keypad) +{ + int row; + u32 row_state = 0; + + for (row = 0; row < keypad->num_row_gpios; row++) + row_state |= row_asserted(keypad, row) ? BIT(row) : 0; + return row_state; +} + /* * This gets the keys from keyboard and reports it to input subsystem */ @@ -111,6 +125,10 @@ static void matrix_keypad_scan(struct work_struct *work) const unsigned short *keycodes = input_dev->keycode; uint32_t new_state[MATRIX_MAX_COLS]; int row, col, code; + u32 init_row_state, new_row_state; + + /* read initial row state to detect changes between scan */ + init_row_state = read_row_state(keypad); /* de-activate all columns for scanning */ activate_all_cols(keypad, false); @@ -125,9 +143,7 @@ static void matrix_keypad_scan(struct work_struct *work) activate_col(keypad, col, true); - for (row = 0; row < keypad->num_row_gpios; row++) - new_state[col] |= - row_asserted(keypad, row) ? BIT(row) : 0; + new_state[col] = read_row_state(keypad); activate_col(keypad, col, false); } @@ -161,6 +177,18 @@ static void matrix_keypad_scan(struct work_struct *work) keypad->scan_pending = false; enable_row_irqs(keypad); } + + /* read new row state and detect if value has changed */ + new_row_state = read_row_state(keypad); + if (init_row_state != new_row_state) { + guard(spinlock_irq)(&keypad->lock); + if (unlikely(keypad->scan_pending || keypad->stopped)) + return; + disable_row_irqs(keypad); + keypad->scan_pending = true; + schedule_delayed_work(&keypad->work, + msecs_to_jiffies(keypad->debounce_ms)); + } } static irqreturn_t matrix_keypad_interrupt(int irq, void *id) @@ -392,6 +420,8 @@ static int matrix_keypad_probe(struct platform_device *pdev) &keypad->debounce_ms); device_property_read_u32(&pdev->dev, "col-scan-delay-us", &keypad->col_scan_delay_us); + device_property_read_u32(&pdev->dev, "all-cols-on-delay-us", + &keypad->all_cols_on_delay_us); err = matrix_keypad_init_gpio(pdev, keypad); if (err) diff --git a/drivers/input/keyboard/max7360-keypad.c b/drivers/input/keyboard/max7360-keypad.c new file mode 100644 index 000000000000..503be952b0a6 --- /dev/null +++ b/drivers/input/keyboard/max7360-keypad.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Bootlin + * + * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> + */ + +#include <linux/bitfield.h> +#include <linux/bitops.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/interrupt.h> +#include <linux/mfd/max7360.h> +#include <linux/mod_devicetable.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> +#include <linux/regmap.h> + +struct max7360_keypad { + struct input_dev *input; + unsigned int rows; + unsigned int cols; + unsigned int debounce_ms; + int irq; + struct regmap *regmap; + unsigned short keycodes[MAX7360_MAX_KEY_ROWS * MAX7360_MAX_KEY_COLS]; +}; + +static irqreturn_t max7360_keypad_irq(int irq, void *data) +{ + struct max7360_keypad *max7360_keypad = data; + struct device *dev = max7360_keypad->input->dev.parent; + unsigned int val; + unsigned int row, col; + unsigned int release; + unsigned int code; + int error; + + error = regmap_read(max7360_keypad->regmap, MAX7360_REG_KEYFIFO, &val); + if (error) { + dev_err(dev, "Failed to read MAX7360 FIFO"); + return IRQ_NONE; + } + + /* FIFO overflow: ignore it and get next event. */ + if (val == MAX7360_FIFO_OVERFLOW) { + dev_warn(dev, "max7360 FIFO overflow"); + error = regmap_read_poll_timeout(max7360_keypad->regmap, MAX7360_REG_KEYFIFO, + val, val != MAX7360_FIFO_OVERFLOW, 0, 1000); + if (error) { + dev_err(dev, "Failed to empty MAX7360 FIFO"); + return IRQ_NONE; + } + } + + if (val == MAX7360_FIFO_EMPTY) { + dev_dbg(dev, "Got a spurious interrupt"); + + return IRQ_NONE; + } + + row = FIELD_GET(MAX7360_FIFO_ROW, val); + col = FIELD_GET(MAX7360_FIFO_COL, val); + release = val & MAX7360_FIFO_RELEASE; + + code = MATRIX_SCAN_CODE(row, col, get_count_order(max7360_keypad->cols)); + + dev_dbg(dev, "key[%d:%d] %s\n", row, col, release ? "release" : "press"); + + input_event(max7360_keypad->input, EV_MSC, MSC_SCAN, code); + input_report_key(max7360_keypad->input, max7360_keypad->keycodes[code], !release); + input_sync(max7360_keypad->input); + + return IRQ_HANDLED; +} + +static int max7360_keypad_open(struct input_dev *pdev) +{ + struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev); + struct device *dev = max7360_keypad->input->dev.parent; + int error; + + /* Somebody is using the device: get out of sleep. */ + error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG, + MAX7360_CFG_SLEEP, MAX7360_CFG_SLEEP); + if (error) + dev_err(dev, "Failed to write max7360 configuration: %d\n", error); + + return error; +} + +static void max7360_keypad_close(struct input_dev *pdev) +{ + struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev); + struct device *dev = max7360_keypad->input->dev.parent; + int error; + + /* Nobody is using the device anymore: go to sleep. */ + error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG, MAX7360_CFG_SLEEP, 0); + if (error) + dev_err(dev, "Failed to write max7360 configuration: %d\n", error); +} + +static int max7360_keypad_hw_init(struct max7360_keypad *max7360_keypad) +{ + struct device *dev = max7360_keypad->input->dev.parent; + unsigned int val; + int error; + + val = max7360_keypad->debounce_ms - MAX7360_DEBOUNCE_MIN; + error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_DEBOUNCE, + MAX7360_DEBOUNCE, + FIELD_PREP(MAX7360_DEBOUNCE, val)); + if (error) + return dev_err_probe(dev, error, + "Failed to write max7360 debounce configuration\n"); + + error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_INTERRUPT, + MAX7360_INTERRUPT_TIME_MASK, + FIELD_PREP(MAX7360_INTERRUPT_TIME_MASK, 1)); + if (error) + return dev_err_probe(dev, error, + "Failed to write max7360 keypad interrupt configuration\n"); + + return 0; +} + +static int max7360_keypad_build_keymap(struct max7360_keypad *max7360_keypad) +{ + struct input_dev *input_dev = max7360_keypad->input; + struct device *dev = input_dev->dev.parent->parent; + struct matrix_keymap_data keymap_data; + const char *propname = "linux,keymap"; + unsigned int max_keys; + int error; + int size; + + size = device_property_count_u32(dev, propname); + if (size <= 0) { + dev_err(dev, "missing or malformed property %s: %d\n", propname, size); + return size < 0 ? size : -EINVAL; + } + + max_keys = max7360_keypad->cols * max7360_keypad->rows; + if (size > max_keys) { + dev_err(dev, "%s size overflow (%d vs max %u)\n", propname, size, max_keys); + return -EINVAL; + } + + u32 *keys __free(kfree) = kmalloc_array(size, sizeof(*keys), GFP_KERNEL); + if (!keys) + return -ENOMEM; + + error = device_property_read_u32_array(dev, propname, keys, size); + if (error) { + dev_err(dev, "failed to read %s property: %d\n", propname, error); + return error; + } + + keymap_data.keymap = keys; + keymap_data.keymap_size = size; + error = matrix_keypad_build_keymap(&keymap_data, NULL, + max7360_keypad->rows, max7360_keypad->cols, + max7360_keypad->keycodes, max7360_keypad->input); + if (error) + return error; + + return 0; +} + +static int max7360_keypad_parse_fw(struct device *dev, + struct max7360_keypad *max7360_keypad, + bool *autorepeat) +{ + int error; + + error = matrix_keypad_parse_properties(dev->parent, &max7360_keypad->rows, + &max7360_keypad->cols); + if (error) + return error; + + if (!max7360_keypad->rows || !max7360_keypad->cols || + max7360_keypad->rows > MAX7360_MAX_KEY_ROWS || + max7360_keypad->cols > MAX7360_MAX_KEY_COLS) { + dev_err(dev, "Invalid number of columns or rows (%ux%u)\n", + max7360_keypad->cols, max7360_keypad->rows); + return -EINVAL; + } + + *autorepeat = device_property_read_bool(dev->parent, "autorepeat"); + + max7360_keypad->debounce_ms = MAX7360_DEBOUNCE_MIN; + error = device_property_read_u32(dev->parent, "keypad-debounce-delay-ms", + &max7360_keypad->debounce_ms); + if (error == -EINVAL) { + dev_info(dev, "Using default keypad-debounce-delay-ms: %u\n", + max7360_keypad->debounce_ms); + } else if (error < 0) { + dev_err(dev, "Failed to read keypad-debounce-delay-ms property\n"); + return error; + } + + if (!in_range(max7360_keypad->debounce_ms, MAX7360_DEBOUNCE_MIN, + MAX7360_DEBOUNCE_MAX - MAX7360_DEBOUNCE_MIN + 1)) { + dev_err(dev, "Invalid keypad-debounce-delay-ms: %u, should be between %u and %u.\n", + max7360_keypad->debounce_ms, MAX7360_DEBOUNCE_MIN, MAX7360_DEBOUNCE_MAX); + return -EINVAL; + } + + return 0; +} + +static int max7360_keypad_probe(struct platform_device *pdev) +{ + struct max7360_keypad *max7360_keypad; + struct device *dev = &pdev->dev; + struct input_dev *input; + struct regmap *regmap; + bool autorepeat; + int error; + int irq; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "Could not get parent regmap\n"); + + irq = fwnode_irq_get_byname(dev_fwnode(dev->parent), "intk"); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get IRQ\n"); + + max7360_keypad = devm_kzalloc(dev, sizeof(*max7360_keypad), GFP_KERNEL); + if (!max7360_keypad) + return -ENOMEM; + + max7360_keypad->regmap = regmap; + + error = max7360_keypad_parse_fw(dev, max7360_keypad, &autorepeat); + if (error) + return error; + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + max7360_keypad->input = input; + + input->id.bustype = BUS_I2C; + input->name = pdev->name; + input->open = max7360_keypad_open; + input->close = max7360_keypad_close; + + error = max7360_keypad_build_keymap(max7360_keypad); + if (error) + return dev_err_probe(dev, error, "Failed to build keymap\n"); + + input_set_capability(input, EV_MSC, MSC_SCAN); + if (autorepeat) + __set_bit(EV_REP, input->evbit); + + input_set_drvdata(input, max7360_keypad); + + error = devm_request_threaded_irq(dev, irq, NULL, max7360_keypad_irq, + IRQF_ONESHOT, + "max7360-keypad", max7360_keypad); + if (error) + return dev_err_probe(dev, error, "Failed to register interrupt\n"); + + error = input_register_device(input); + if (error) + return dev_err_probe(dev, error, "Could not register input device\n"); + + error = max7360_keypad_hw_init(max7360_keypad); + if (error) + return dev_err_probe(dev, error, "Failed to initialize max7360 keypad\n"); + + device_init_wakeup(dev, true); + error = dev_pm_set_wake_irq(dev, irq); + if (error) + dev_warn(dev, "Failed to set up wakeup irq: %d\n", error); + + return 0; +} + +static void max7360_keypad_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); +} + +static struct platform_driver max7360_keypad_driver = { + .driver = { + .name = "max7360-keypad", + }, + .probe = max7360_keypad_probe, + .remove = max7360_keypad_remove, +}; +module_platform_driver(max7360_keypad_driver); + +MODULE_DESCRIPTION("MAX7360 Keypad driver"); +MODULE_AUTHOR("Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index bd1a944ded46..47edc161ec77 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -295,8 +295,6 @@ static int mpr_touchkey_probe(struct i2c_client *client) return error; i2c_set_clientdata(client, mpr121); - device_init_wakeup(dev, - device_property_read_bool(dev, "wakeup-source")); return 0; } @@ -305,9 +303,6 @@ static int mpr_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (device_may_wakeup(&client->dev)) - enable_irq_wake(client->irq); - i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00); return 0; @@ -318,9 +313,6 @@ static int mpr_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) - disable_irq_wake(client->irq); - i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, mpr121->keycount); diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c index 5ad6be914160..c78d9f6d97c4 100644 --- a/drivers/input/keyboard/mtk-pmic-keys.c +++ b/drivers/input/keyboard/mtk-pmic-keys.c @@ -12,6 +12,7 @@ #include <linux/mfd/mt6331/registers.h> #include <linux/mfd/mt6357/registers.h> #include <linux/mfd/mt6358/registers.h> +#include <linux/mfd/mt6359/registers.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/registers.h> #include <linux/module.h> @@ -54,6 +55,7 @@ struct mtk_pmic_regs { const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT]; u32 pmic_rst_reg; u32 rst_lprst_mask; /* Long-press reset timeout bitmask */ + bool key_release_irq; }; static const struct mtk_pmic_regs mt6397_regs = { @@ -115,6 +117,21 @@ static const struct mtk_pmic_regs mt6358_regs = { MTK_PMIC_HOMEKEY_RST), .pmic_rst_reg = MT6358_TOP_RST_MISC, .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, + .key_release_irq = true, +}; + +static const struct mtk_pmic_regs mt6359_regs = { + .keys_regs[MTK_PMIC_PWRKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS, + 0x2, MT6359_PSC_TOP_INT_CON0, 0x5, + MTK_PMIC_PWRKEY_RST), + .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS, + 0x8, MT6359_PSC_TOP_INT_CON0, 0xa, + MTK_PMIC_HOMEKEY_RST), + .pmic_rst_reg = MT6359_TOP_RST_MISC, + .rst_lprst_mask = MTK_PMIC_RST_DU_MASK, + .key_release_irq = true, }; struct mtk_pmic_keys_info { @@ -147,8 +164,8 @@ static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys, u32 value, mask; int error; - kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs; - kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs; + kregs_home = ®s->keys_regs[MTK_PMIC_HOMEKEY_INDEX]; + kregs_pwr = ®s->keys_regs[MTK_PMIC_PWRKEY_INDEX]; error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec", &long_press_debounce); @@ -297,6 +314,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = { .compatible = "mediatek,mt6358-keys", .data = &mt6358_regs, }, { + .compatible = "mediatek,mt6359-keys", + .data = &mt6359_regs, + }, { /* sentinel */ } }; @@ -351,7 +371,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) if (keys->keys[index].irq < 0) return keys->keys[index].irq; - if (of_device_is_compatible(node, "mediatek,mt6358-keys")) { + if (mtk_pmic_regs->key_release_irq) { keys->keys[index].irq_r = platform_get_irq_byname(pdev, irqnames_r[index]); diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 71e0a3f830dd..e60d1181dad0 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -68,7 +68,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - nkbd = kzalloc(sizeof(*nkbd), GFP_KERNEL); + nkbd = kzalloc_obj(*nkbd); input_dev = input_allocate_device(); if (!nkbd || !input_dev) goto fail1; diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 9e13f3f70a81..589f51d430c7 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c @@ -193,7 +193,7 @@ static int omap_kp_probe(struct platform_device *pdev) row_shift = get_count_order(pdata->cols); keycodemax = pdata->rows << row_shift; - omap_kp = kzalloc(struct_size(omap_kp, keymap, keycodemax), GFP_KERNEL); + omap_kp = kzalloc_flex(*omap_kp, keymap, keycodemax); input_dev = input_allocate_device(); if (!omap_kp || !input_dev) { kfree(omap_kp); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index bffe89c0717a..e783244d0c91 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -193,7 +193,6 @@ static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return IRQ_HANDLED; @@ -231,7 +230,6 @@ static int omap4_keypad_open(struct input_dev *input) enable_irq(keypad_data->irq); out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return error; @@ -265,7 +263,6 @@ static void omap4_keypad_close(struct input_dev *input) enable_irq(keypad_data->irq); clk_disable_unprepare(keypad_data->fck); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } @@ -404,7 +401,6 @@ static int omap4_keypad_probe(struct platform_device *pdev) omap4_keypad_stop(keypad_data); } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); if (error) return error; diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 38ec619aa359..4519eecb317b 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -12,7 +12,8 @@ * on some suggestions by Nicolas Pitre <nico@fluxnic.net>. */ - +#include <linux/bits.h> +#include <linux/bitfield.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -20,124 +21,148 @@ #include <linux/io.h> #include <linux/device.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/input/matrix_keypad.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/platform_data/keypad-pxa27x.h> /* * Keypad Controller registers */ -#define KPC 0x0000 /* Keypad Control register */ -#define KPDK 0x0008 /* Keypad Direct Key register */ -#define KPREC 0x0010 /* Keypad Rotary Encoder register */ -#define KPMK 0x0018 /* Keypad Matrix Key register */ -#define KPAS 0x0020 /* Keypad Automatic Scan register */ +#define KPC 0x0000 /* Keypad Control register */ +#define KPDK 0x0008 /* Keypad Direct Key register */ +#define KPREC 0x0010 /* Keypad Rotary Encoder register */ +#define KPMK 0x0018 /* Keypad Matrix Key register */ +#define KPAS 0x0020 /* Keypad Automatic Scan register */ /* Keypad Automatic Scan Multiple Key Presser register 0-3 */ -#define KPASMKP0 0x0028 -#define KPASMKP1 0x0030 -#define KPASMKP2 0x0038 -#define KPASMKP3 0x0040 -#define KPKDI 0x0048 +#define KPASMKP0 0x0028 +#define KPASMKP1 0x0030 +#define KPASMKP2 0x0038 +#define KPASMKP3 0x0040 +#define KPKDI 0x0048 /* bit definitions */ -#define KPC_MKRN(n) ((((n) - 1) & 0x7) << 26) /* matrix key row number */ -#define KPC_MKCN(n) ((((n) - 1) & 0x7) << 23) /* matrix key column number */ -#define KPC_DKN(n) ((((n) - 1) & 0x7) << 6) /* direct key number */ - -#define KPC_AS (0x1 << 30) /* Automatic Scan bit */ -#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */ -#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */ -#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */ - -#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */ -#define KPC_MS_ALL (0xff << 13) - -#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */ -#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */ -#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */ -#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */ -#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */ -#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */ -#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */ -#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */ -#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */ - -#define KPDK_DKP (0x1 << 31) -#define KPDK_DK(n) ((n) & 0xff) - -#define KPREC_OF1 (0x1 << 31) -#define kPREC_UF1 (0x1 << 30) -#define KPREC_OF0 (0x1 << 15) -#define KPREC_UF0 (0x1 << 14) - -#define KPREC_RECOUNT0(n) ((n) & 0xff) -#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff) - -#define KPMK_MKP (0x1 << 31) -#define KPAS_SO (0x1 << 31) -#define KPASMKPx_SO (0x1 << 31) - -#define KPAS_MUKP(n) (((n) >> 26) & 0x1f) -#define KPAS_RP(n) (((n) >> 4) & 0xf) -#define KPAS_CP(n) ((n) & 0xf) - -#define KPASMKP_MKC_MASK (0xff) +#define KPC_MKRN_MASK GENMASK(28, 26) +#define KPC_MKCN_MASK GENMASK(25, 23) +#define KPC_DKN_MASK GENMASK(8, 6) +#define KPC_MKRN(n) FIELD_PREP(KPC_MKRN_MASK, (n) - 1) +#define KPC_MKCN(n) FIELD_PREP(KPC_MKCN_MASK, (n) - 1) +#define KPC_DKN(n) FIELD_PREP(KPC_DKN_MASK, (n) - 1) + +#define KPC_AS BIT(30) /* Automatic Scan bit */ +#define KPC_ASACT BIT(29) /* Automatic Scan on Activity */ +#define KPC_MI BIT(22) /* Matrix interrupt bit */ +#define KPC_IMKP BIT(21) /* Ignore Multiple Key Press */ + +#define KPC_MS(n) BIT(13 + (n)) /* Matrix scan line 'n' */ +#define KPC_MS_ALL GENMASK(20, 13) + +#define KPC_ME BIT(12) /* Matrix Keypad Enable */ +#define KPC_MIE BIT(11) /* Matrix Interrupt Enable */ +#define KPC_DK_DEB_SEL BIT(9) /* Direct Keypad Debounce Select */ +#define KPC_DI BIT(5) /* Direct key interrupt bit */ +#define KPC_RE_ZERO_DEB BIT(4) /* Rotary Encoder Zero Debounce */ +#define KPC_REE1 BIT(3) /* Rotary Encoder1 Enable */ +#define KPC_REE0 BIT(2) /* Rotary Encoder0 Enable */ +#define KPC_DE BIT(1) /* Direct Keypad Enable */ +#define KPC_DIE BIT(0) /* Direct Keypad interrupt Enable */ + +#define KPDK_DKP BIT(31) +#define KPDK_DK_MASK GENMASK(7, 0) +#define KPDK_DK(n) FIELD_GET(KPDK_DK_MASK, n) + +#define KPREC_OF1 BIT(31) +#define KPREC_UF1 BIT(30) +#define KPREC_OF0 BIT(15) +#define KPREC_UF0 BIT(14) + +#define KPREC_RECOUNT0_MASK GENMASK(7, 0) +#define KPREC_RECOUNT1_MASK GENMASK(23, 16) +#define KPREC_RECOUNT0(n) FIELD_GET(KPREC_RECOUNT0_MASK, n) +#define KPREC_RECOUNT1(n) FIELD_GET(KPREC_RECOUNT1_MASK, n) + +#define KPMK_MKP BIT(31) +#define KPAS_SO BIT(31) +#define KPASMKPx_SO BIT(31) + +#define KPAS_MUKP_MASK GENMASK(30, 26) +#define KPAS_RP_MASK GENMASK(7, 4) +#define KPAS_CP_MASK GENMASK(3, 0) +#define KPAS_MUKP(n) FIELD_GET(KPAS_MUKP_MASK, n) +#define KPAS_RP(n) FIELD_GET(KPAS_RP_MASK, n) +#define KPAS_CP(n) FIELD_GET(KPAS_CP_MASK, n) + +#define KPASMKP_MKC_MASK GENMASK(7, 0) #define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) #define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off)) +#define MAX_MATRIX_KEY_ROWS 8 +#define MAX_MATRIX_KEY_COLS 8 +#define MAX_DIRECT_KEY_NUM 8 +#define MAX_ROTARY_ENCODERS 2 + #define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) #define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM) -struct pxa27x_keypad { - const struct pxa27x_keypad_platform_data *pdata; +struct pxa27x_keypad_rotary { + unsigned short *key_codes; + int rel_code; + bool enabled; +}; +struct pxa27x_keypad { struct clk *clk; struct input_dev *input_dev; void __iomem *mmio_base; int irq; - unsigned short keycodes[MAX_KEYPAD_KEYS]; - int rotary_rel_code[2]; - + unsigned int matrix_key_rows; + unsigned int matrix_key_cols; unsigned int row_shift; + unsigned int direct_key_num; + unsigned int direct_key_mask; + bool direct_key_low_active; + + /* key debounce interval */ + unsigned int debounce_interval; + + unsigned short keycodes[MAX_KEYPAD_KEYS]; + /* state row bits of each column scan */ - uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS]; - uint32_t direct_key_state; + u32 matrix_key_state[MAX_MATRIX_KEY_COLS]; + u32 direct_key_state; - unsigned int direct_key_mask; + struct pxa27x_keypad_rotary rotary[MAX_ROTARY_ENCODERS]; }; -#ifdef CONFIG_OF -static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_matrix_key_parse(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - u32 rows, cols; int error; - error = matrix_keypad_parse_properties(dev, &rows, &cols); + error = matrix_keypad_parse_properties(dev, &keypad->matrix_key_rows, + &keypad->matrix_key_cols); if (error) return error; - if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) { + if (keypad->matrix_key_rows > MAX_MATRIX_KEY_ROWS || + keypad->matrix_key_cols > MAX_MATRIX_KEY_COLS) { dev_err(dev, "rows or cols exceeds maximum value\n"); return -EINVAL; } - pdata->matrix_key_rows = rows; - pdata->matrix_key_cols = cols; + keypad->row_shift = get_count_order(keypad->matrix_key_cols); error = matrix_keypad_build_keymap(NULL, NULL, - pdata->matrix_key_rows, - pdata->matrix_key_cols, + keypad->matrix_key_rows, + keypad->matrix_key_cols, keypad->keycodes, input_dev); if (error) return error; @@ -145,20 +170,17 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad, return 0; } -static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_direct_key_parse(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; - const __be16 *prop; unsigned short code; - unsigned int proplen, size; + int count; int i; int error; - error = of_property_read_u32(np, "marvell,direct-key-count", - &pdata->direct_key_num); + error = device_property_read_u32(dev, "marvell,direct-key-count", + &keypad->direct_key_num); if (error) { /* * If do not have marvel,direct-key-count defined, @@ -167,151 +189,121 @@ static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad, return error == -EINVAL ? 0 : error; } - error = of_property_read_u32(np, "marvell,direct-key-mask", - &pdata->direct_key_mask); + error = device_property_read_u32(dev, "marvell,direct-key-mask", + &keypad->direct_key_mask); if (error) { if (error != -EINVAL) return error; /* * If marvell,direct-key-mask is not defined, driver will use - * default value. Default value is set when configure the keypad. + * a default value based on number of direct keys set up. + * The default value is calculated in pxa27x_keypad_config(). */ - pdata->direct_key_mask = 0; + keypad->direct_key_mask = 0; } - pdata->direct_key_low_active = of_property_read_bool(np, - "marvell,direct-key-low-active"); - - prop = of_get_property(np, "marvell,direct-key-map", &proplen); - if (!prop) - return -EINVAL; + keypad->direct_key_low_active = + device_property_read_bool(dev, "marvell,direct-key-low-active"); - if (proplen % sizeof(u16)) + count = device_property_count_u16(dev, "marvell,direct-key-map"); + if (count <= 0 || count > MAX_DIRECT_KEY_NUM) return -EINVAL; - size = proplen / sizeof(u16); + error = device_property_read_u16_array(dev, "marvell,direct-key-map", + &keypad->keycodes[MAX_MATRIX_KEY_NUM], + count); - /* Only MAX_DIRECT_KEY_NUM is accepted.*/ - if (size > MAX_DIRECT_KEY_NUM) - return -EINVAL; - - for (i = 0; i < size; i++) { - code = be16_to_cpup(prop + i); - keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code; + for (i = 0; i < count; i++) { + code = keypad->keycodes[MAX_MATRIX_KEY_NUM + i]; __set_bit(code, input_dev->keybit); } return 0; } -static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad, - struct pxa27x_keypad_platform_data *pdata) +static int pxa27x_keypad_rotary_parse(struct pxa27x_keypad *keypad) { - const __be32 *prop; - int i, relkey_ret; - unsigned int code, proplen; - const char *rotaryname[2] = { - "marvell,rotary0", "marvell,rotary1"}; - const char relkeyname[] = {"marvell,rotary-rel-key"}; + static const char * const rotaryname[] = { "marvell,rotary0", "marvell,rotary1" }; struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; - - relkey_ret = of_property_read_u32(np, relkeyname, &code); - /* if can read correct rotary key-code, we do not need this. */ - if (relkey_ret == 0) { - unsigned short relcode; + struct pxa27x_keypad_rotary *encoder; + unsigned int code; + int i; + int error; - /* rotary0 taks lower half, rotary1 taks upper half. */ - relcode = code & 0xffff; - pdata->rotary0_rel_code = (code & 0xffff); - __set_bit(relcode, input_dev->relbit); + error = device_property_read_u32(dev, "marvell,rotary-rel-key", &code); + if (!error) { + for (i = 0; i < MAX_ROTARY_ENCODERS; i++, code >>= 16) { + encoder = &keypad->rotary[i]; + encoder->enabled = true; + encoder->rel_code = code & 0xffff; + input_set_capability(input_dev, EV_REL, encoder->rel_code); + } - relcode = code >> 16; - pdata->rotary1_rel_code = relcode; - __set_bit(relcode, input_dev->relbit); + return 0; } - for (i = 0; i < 2; i++) { - prop = of_get_property(np, rotaryname[i], &proplen); + for (i = 0; i < MAX_ROTARY_ENCODERS; i++) { + encoder = &keypad->rotary[i]; + /* * If the prop is not set, it means keypad does not need * initialize the rotaryX. */ - if (!prop) + if (!device_property_present(dev, rotaryname[i])) continue; - code = be32_to_cpup(prop); + error = device_property_read_u32(dev, rotaryname[i], &code); + if (error) + return error; + /* * Not all up/down key code are valid. * Now we depends on direct-rel-code. */ - if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) { - return relkey_ret; - } else { - unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1); - unsigned short keycode; - - keycode = code & 0xffff; - keypad->keycodes[n] = keycode; - __set_bit(keycode, input_dev->keybit); - - keycode = code >> 16; - keypad->keycodes[n + 1] = keycode; - __set_bit(keycode, input_dev->keybit); - - if (i == 0) - pdata->rotary0_rel_code = -1; - else - pdata->rotary1_rel_code = -1; - } - if (i == 0) - pdata->enable_rotary0 = 1; - else - pdata->enable_rotary1 = 1; - } + if (!(code & 0xffff) || !(code >> 16)) + return -EINVAL; + + encoder->enabled = true; + encoder->rel_code = -1; + encoder->key_codes = &keypad->keycodes[MAX_MATRIX_KEY_NUM + i * 2]; + encoder->key_codes[0] = code & 0xffff; + encoder->key_codes[1] = code >> 16; - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; + input_set_capability(input_dev, EV_KEY, encoder->key_codes[0]); + input_set_capability(input_dev, EV_KEY, encoder->key_codes[1]); + } return 0; } -static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) +static int pxa27x_keypad_parse_properties(struct pxa27x_keypad *keypad) { struct input_dev *input_dev = keypad->input_dev; struct device *dev = input_dev->dev.parent; - struct device_node *np = dev->of_node; - struct pxa27x_keypad_platform_data *pdata; int error; - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - dev_err(dev, "failed to allocate memory for pdata\n"); - return -ENOMEM; - } - - error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata); + error = pxa27x_keypad_matrix_key_parse(keypad); if (error) { dev_err(dev, "failed to parse matrix key\n"); return error; } - error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata); + error = pxa27x_keypad_direct_key_parse(keypad); if (error) { dev_err(dev, "failed to parse direct key\n"); return error; } - error = pxa27x_keypad_rotary_parse_dt(keypad, pdata); + error = pxa27x_keypad_rotary_parse(keypad); if (error) { dev_err(dev, "failed to parse rotary key\n"); return error; } - error = of_property_read_u32(np, "marvell,debounce-interval", - &pdata->debounce_interval); + error = device_property_read_u32(dev, "marvell,debounce-interval", + &keypad->debounce_interval); if (error) { dev_err(dev, "failed to parse debounce-interval\n"); return error; @@ -323,95 +315,15 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) */ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - keypad->pdata = pdata; - return 0; -} - -#else - -static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) -{ - dev_info(keypad->input_dev->dev.parent, "missing platform data\n"); - - return -EINVAL; -} - -#endif - -static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad) -{ - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - struct input_dev *input_dev = keypad->input_dev; - unsigned short keycode; - int i; - int error; - - error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL, - pdata->matrix_key_rows, - pdata->matrix_key_cols, - keypad->keycodes, input_dev); - if (error) - return error; - - /* - * The keycodes may not only include matrix keys but also the direct - * or rotary keys. - */ - input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); - - /* For direct keys. */ - for (i = 0; i < pdata->direct_key_num; i++) { - keycode = pdata->direct_key_map[i]; - keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode; - __set_bit(keycode, input_dev->keybit); - } - - if (pdata->enable_rotary0) { - if (pdata->rotary0_up_key && pdata->rotary0_down_key) { - keycode = pdata->rotary0_up_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode; - __set_bit(keycode, input_dev->keybit); - - keycode = pdata->rotary0_down_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode; - __set_bit(keycode, input_dev->keybit); - - keypad->rotary_rel_code[0] = -1; - } else { - keypad->rotary_rel_code[0] = pdata->rotary0_rel_code; - __set_bit(pdata->rotary0_rel_code, input_dev->relbit); - } - } - - if (pdata->enable_rotary1) { - if (pdata->rotary1_up_key && pdata->rotary1_down_key) { - keycode = pdata->rotary1_up_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode; - __set_bit(keycode, input_dev->keybit); - - keycode = pdata->rotary1_down_key; - keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode; - __set_bit(keycode, input_dev->keybit); - - keypad->rotary_rel_code[1] = -1; - } else { - keypad->rotary_rel_code[1] = pdata->rotary1_rel_code; - __set_bit(pdata->rotary1_rel_code, input_dev->relbit); - } - } - - __clear_bit(KEY_RESERVED, input_dev->keybit); - return 0; } static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; int row, col, num_keys_pressed = 0; - uint32_t new_state[MAX_MATRIX_KEY_COLS]; - uint32_t kpas = keypad_readl(KPAS); + u32 new_state[MAX_MATRIX_KEY_COLS]; + u32 kpas = keypad_readl(KPAS); num_keys_pressed = KPAS_MUKP(kpas); @@ -425,19 +337,19 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) row = KPAS_RP(kpas); /* if invalid row/col, treat as no key pressed */ - if (col >= pdata->matrix_key_cols || - row >= pdata->matrix_key_rows) + if (col >= keypad->matrix_key_cols || + row >= keypad->matrix_key_rows) goto scan; - new_state[col] = (1 << row); + new_state[col] = BIT(row); goto scan; } if (num_keys_pressed > 1) { - uint32_t kpasmkp0 = keypad_readl(KPASMKP0); - uint32_t kpasmkp1 = keypad_readl(KPASMKP1); - uint32_t kpasmkp2 = keypad_readl(KPASMKP2); - uint32_t kpasmkp3 = keypad_readl(KPASMKP3); + u32 kpasmkp0 = keypad_readl(KPASMKP0); + u32 kpasmkp1 = keypad_readl(KPASMKP1); + u32 kpasmkp2 = keypad_readl(KPASMKP2); + u32 kpasmkp3 = keypad_readl(KPASMKP3); new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK; new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK; @@ -449,23 +361,23 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad) new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK; } scan: - for (col = 0; col < pdata->matrix_key_cols; col++) { - uint32_t bits_changed; + for (col = 0; col < keypad->matrix_key_cols; col++) { + u32 bits_changed; int code; bits_changed = keypad->matrix_key_state[col] ^ new_state[col]; if (bits_changed == 0) continue; - for (row = 0; row < pdata->matrix_key_rows; row++) { - if ((bits_changed & (1 << row)) == 0) + for (row = 0; row < keypad->matrix_key_rows; row++) { + if ((bits_changed & BIT(row)) == 0) continue; code = MATRIX_SCAN_CODE(row, col, keypad->row_shift); input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, keypad->keycodes[code], - new_state[col] & (1 << row)); + new_state[col] & BIT(row)); } } input_sync(input_dev); @@ -474,7 +386,7 @@ scan: #define DEFAULT_KPREC (0x007f007f) -static inline int rotary_delta(uint32_t kprec) +static inline int rotary_delta(u32 kprec) { if (kprec & KPREC_OF0) return (kprec & 0xff) + 0x7f; @@ -486,14 +398,16 @@ static inline int rotary_delta(uint32_t kprec) static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) { + struct pxa27x_keypad_rotary *encoder = &keypad->rotary[r]; struct input_dev *dev = keypad->input_dev; - if (delta == 0) + if (!encoder->enabled || delta == 0) return; - if (keypad->rotary_rel_code[r] == -1) { - int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1); - unsigned char keycode = keypad->keycodes[code]; + if (encoder->rel_code == -1) { + int idx = delta > 0 ? 0 : 1; + int code = MAX_MATRIX_KEY_NUM + 2 * r + idx; + unsigned char keycode = encoder->key_codes[idx]; /* simulate a press-n-release */ input_event(dev, EV_MSC, MSC_SCAN, code); @@ -503,45 +417,43 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta) input_report_key(dev, keycode, 0); input_sync(dev); } else { - input_report_rel(dev, keypad->rotary_rel_code[r], delta); + input_report_rel(dev, encoder->rel_code, delta); input_sync(dev); } } static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - uint32_t kprec; + u32 kprec; + int i; /* read and reset to default count value */ kprec = keypad_readl(KPREC); keypad_writel(KPREC, DEFAULT_KPREC); - if (pdata->enable_rotary0) + for (i = 0; i < MAX_ROTARY_ENCODERS; i++) { report_rotary_event(keypad, 0, rotary_delta(kprec)); - - if (pdata->enable_rotary1) - report_rotary_event(keypad, 1, rotary_delta(kprec >> 16)); + kprec >>= 16; + } } static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; struct input_dev *input_dev = keypad->input_dev; unsigned int new_state; - uint32_t kpdk, bits_changed; + u32 kpdk, bits_changed; int i; kpdk = keypad_readl(KPDK); - if (pdata->enable_rotary0 || pdata->enable_rotary1) + if (keypad->rotary[0].enabled || keypad->rotary[1].enabled) pxa27x_keypad_scan_rotary(keypad); /* * The KPDR_DK only output the key pin level, so it relates to board, * and low level may be active. */ - if (pdata->direct_key_low_active) + if (keypad->direct_key_low_active) new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask; else new_state = KPDK_DK(kpdk) & keypad->direct_key_mask; @@ -551,34 +463,24 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad) if (bits_changed == 0) return; - for (i = 0; i < pdata->direct_key_num; i++) { - if (bits_changed & (1 << i)) { + for (i = 0; i < keypad->direct_key_num; i++) { + if (bits_changed & BIT(i)) { int code = MAX_MATRIX_KEY_NUM + i; input_event(input_dev, EV_MSC, MSC_SCAN, code); input_report_key(input_dev, keypad->keycodes[code], - new_state & (1 << i)); + new_state & BIT(i)); } } input_sync(input_dev); keypad->direct_key_state = new_state; } -static void clear_wakeup_event(struct pxa27x_keypad *keypad) -{ - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; - - if (pdata->clear_wakeup_event) - (pdata->clear_wakeup_event)(); -} - static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) { struct pxa27x_keypad *keypad = dev_id; unsigned long kpc = keypad_readl(KPC); - clear_wakeup_event(keypad); - if (kpc & KPC_DI) pxa27x_keypad_scan_direct(keypad); @@ -590,7 +492,6 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id) static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) { - const struct pxa27x_keypad_platform_data *pdata = keypad->pdata; unsigned int mask = 0, direct_key_num = 0; unsigned long kpc = 0; @@ -598,36 +499,34 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) keypad_readl(KPC); /* enable matrix keys with automatic scan */ - if (pdata->matrix_key_rows && pdata->matrix_key_cols) { + if (keypad->matrix_key_rows && keypad->matrix_key_cols) { kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL; - kpc |= KPC_MKRN(pdata->matrix_key_rows) | - KPC_MKCN(pdata->matrix_key_cols); + kpc |= KPC_MKRN(keypad->matrix_key_rows) | + KPC_MKCN(keypad->matrix_key_cols); } /* enable rotary key, debounce interval same as direct keys */ - if (pdata->enable_rotary0) { + if (keypad->rotary[0].enabled) { mask |= 0x03; direct_key_num = 2; kpc |= KPC_REE0; } - if (pdata->enable_rotary1) { + if (keypad->rotary[1].enabled) { mask |= 0x0c; direct_key_num = 4; kpc |= KPC_REE1; } - if (pdata->direct_key_num > direct_key_num) - direct_key_num = pdata->direct_key_num; + if (keypad->direct_key_num > direct_key_num) + direct_key_num = keypad->direct_key_num; /* * Direct keys usage may not start from KP_DKIN0, check the platfrom * mask data to config the specific. */ - if (pdata->direct_key_mask) - keypad->direct_key_mask = pdata->direct_key_mask; - else - keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask; + if (!keypad->direct_key_mask) + keypad->direct_key_mask = GENMASK(direct_key_num - 1, 0) & ~mask; /* enable direct key */ if (direct_key_num) @@ -635,7 +534,7 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad) keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB); keypad_writel(KPREC, DEFAULT_KPREC); - keypad_writel(KPKDI, pdata->debounce_interval); + keypad_writel(KPKDI, keypad->debounce_interval); } static int pxa27x_keypad_open(struct input_dev *dev) @@ -709,19 +608,12 @@ static int pxa27x_keypad_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops, pxa27x_keypad_suspend, pxa27x_keypad_resume); - static int pxa27x_keypad_probe(struct platform_device *pdev) { - const struct pxa27x_keypad_platform_data *pdata = - dev_get_platdata(&pdev->dev); - struct device_node *np = pdev->dev.of_node; struct pxa27x_keypad *keypad; struct input_dev *input_dev; - int irq, error; - - /* Driver need build keycode from device tree or pdata */ - if (!np && !pdata) - return -EINVAL; + int irq; + int error; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -736,7 +628,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) if (!input_dev) return -ENOMEM; - keypad->pdata = pdata; keypad->input_dev = input_dev; keypad->irq = irq; @@ -765,29 +656,12 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_set_capability(input_dev, EV_MSC, MSC_SCAN); - if (pdata) { - error = pxa27x_keypad_build_keycode(keypad); - } else { - error = pxa27x_keypad_build_keycode_from_dt(keypad); - /* - * Data that we get from DT resides in dynamically - * allocated memory so we need to update our pdata - * pointer. - */ - pdata = keypad->pdata; - } + error = pxa27x_keypad_parse_properties(keypad); if (error) { - dev_err(&pdev->dev, "failed to build keycode\n"); + dev_err(&pdev->dev, "failed to parse keypad properties\n"); return error; } - keypad->row_shift = get_count_order(pdata->matrix_key_cols); - - if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) || - (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) { - input_dev->evbit[0] |= BIT_MASK(EV_REL); - } - error = devm_request_irq(&pdev->dev, irq, pxa27x_keypad_irq_handler, 0, pdev->name, keypad); if (error) { diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c index bce8157d1871..f9f480c91032 100644 --- a/drivers/input/keyboard/qt1050.c +++ b/drivers/input/keyboard/qt1050.c @@ -435,8 +435,7 @@ static int qt1050_probe(struct i2c_client *client) int err; /* Check basic functionality */ - err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); - if (!err) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", dev_driver_string(&client->adapter->dev)); return -ENODEV; diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index b3db2c7d0957..b255b997e279 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -133,8 +133,7 @@ static int qt1070_probe(struct i2c_client *client) int i; int err; - err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); - if (!err) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", dev_driver_string(&client->adapter->dev)); return -ENODEV; diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 9f1049aa3048..17127269e3f0 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -7,6 +7,7 @@ * Author: Donghwa Lee <dh09.lee@samsung.com> */ +#include <linux/bits.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/err.h> @@ -29,11 +30,11 @@ #define SAMSUNG_KEYIFFC 0x10 /* SAMSUNG_KEYIFCON */ -#define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0) -#define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1) -#define SAMSUNG_KEYIFCON_DF_EN (1 << 2) -#define SAMSUNG_KEYIFCON_FC_EN (1 << 3) -#define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4) +#define SAMSUNG_KEYIFCON_INT_F_EN BIT(0) +#define SAMSUNG_KEYIFCON_INT_R_EN BIT(1) +#define SAMSUNG_KEYIFCON_DF_EN BIT(2) +#define SAMSUNG_KEYIFCON_FC_EN BIT(3) +#define SAMSUNG_KEYIFCON_WAKEUPEN BIT(4) /* SAMSUNG_KEYIFSTSCLR */ #define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0) @@ -44,8 +45,7 @@ #define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16 /* SAMSUNG_KEYIFCOL */ -#define SAMSUNG_KEYIFCOL_MASK (0xff << 0) -#define S5PV210_KEYIFCOLEN_MASK (0xff << 8) +#define SAMSUNG_KEYIFCOL_MASK 0xff /* SAMSUNG_KEYIFROW */ #define SAMSUNG_KEYIFROW_MASK (0xff << 0) @@ -54,12 +54,12 @@ /* SAMSUNG_KEYIFFC */ #define SAMSUNG_KEYIFFC_MASK (0x3ff << 0) -enum samsung_keypad_type { - KEYPAD_TYPE_SAMSUNG, - KEYPAD_TYPE_S5PV210, +struct samsung_chip_info { + unsigned int column_shift; }; struct samsung_keypad { + const struct samsung_chip_info *chip; struct input_dev *input_dev; struct platform_device *pdev; struct clk *clk; @@ -68,7 +68,6 @@ struct samsung_keypad { bool stopped; bool wake_enabled; int irq; - enum samsung_keypad_type type; unsigned int row_shift; unsigned int rows; unsigned int cols; @@ -83,19 +82,14 @@ static void samsung_keypad_scan(struct samsung_keypad *keypad, unsigned int val; for (col = 0; col < keypad->cols; col++) { - if (keypad->type == KEYPAD_TYPE_S5PV210) { - val = S5PV210_KEYIFCOLEN_MASK; - val &= ~(1 << col) << 8; - } else { - val = SAMSUNG_KEYIFCOL_MASK; - val &= ~(1 << col); - } + val = SAMSUNG_KEYIFCOL_MASK & ~BIT(col); + val <<= keypad->chip->column_shift; writel(val, keypad->base + SAMSUNG_KEYIFCOL); mdelay(1); val = readl(keypad->base + SAMSUNG_KEYIFROW); - row_state[col] = ~val & ((1 << keypad->rows) - 1); + row_state[col] = ~val & GENMASK(keypad->rows - 1, 0); } /* KEYIFCOL reg clear */ @@ -119,10 +113,10 @@ static bool samsung_keypad_report(struct samsung_keypad *keypad, continue; for (row = 0; row < keypad->rows; row++) { - if (!(changed & (1 << row))) + if (!(changed & BIT(row))) continue; - pressed = row_state[col] & (1 << row); + pressed = row_state[col] & BIT(row); dev_dbg(&keypad->input_dev->dev, "key %s, row: %d, col: %d\n", @@ -314,11 +308,11 @@ static int samsung_keypad_probe(struct platform_device *pdev) { const struct samsung_keypad_platdata *pdata; const struct matrix_keymap_data *keymap_data; + const struct platform_device_id *id; struct samsung_keypad *keypad; struct resource *res; struct input_dev *input_dev; unsigned int row_shift; - unsigned int keymap_size; int error; pdata = dev_get_platdata(&pdev->dev); @@ -345,12 +339,16 @@ static int samsung_keypad_probe(struct platform_device *pdev) pdata->cfg_gpio(pdata->rows, pdata->cols); row_shift = get_count_order(pdata->cols); - keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]); - keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size, + keypad = devm_kzalloc(&pdev->dev, + struct_size(keypad, keycodes, + pdata->rows << row_shift), GFP_KERNEL); + if (!keypad) + return -ENOMEM; + input_dev = devm_input_allocate_device(&pdev->dev); - if (!keypad || !input_dev) + if (!input_dev) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -361,18 +359,12 @@ static int samsung_keypad_probe(struct platform_device *pdev) if (!keypad->base) return -EBUSY; - keypad->clk = devm_clk_get(&pdev->dev, "keypad"); + keypad->clk = devm_clk_get_prepared(&pdev->dev, "keypad"); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get keypad clk\n"); return PTR_ERR(keypad->clk); } - error = clk_prepare(keypad->clk); - if (error) { - dev_err(&pdev->dev, "keypad clock prepare failed\n"); - return error; - } - keypad->input_dev = input_dev; keypad->pdev = pdev; keypad->row_shift = row_shift; @@ -381,15 +373,20 @@ static int samsung_keypad_probe(struct platform_device *pdev) keypad->stopped = true; init_waitqueue_head(&keypad->wait); - if (pdev->dev.of_node) - keypad->type = of_device_is_compatible(pdev->dev.of_node, - "samsung,s5pv210-keypad"); - else - keypad->type = platform_get_device_id(pdev)->driver_data; + keypad->chip = device_get_match_data(&pdev->dev); + if (!keypad->chip) { + id = platform_get_device_id(pdev); + if (id) + keypad->chip = (const void *)id->driver_data; + } + + if (!keypad->chip) { + dev_err(&pdev->dev, "Unable to determine chip type"); + return -EINVAL; + } input_dev->name = pdev->name; input_dev->id.bustype = BUS_HOST; - input_dev->dev.parent = &pdev->dev; input_dev->open = samsung_keypad_open; input_dev->close = samsung_keypad_close; @@ -399,7 +396,7 @@ static int samsung_keypad_probe(struct platform_device *pdev) keypad->keycodes, input_dev); if (error) { dev_err(&pdev->dev, "failed to build keymap\n"); - goto err_unprepare_clk; + return error; } input_set_capability(input_dev, EV_MSC, MSC_SCAN); @@ -411,7 +408,7 @@ static int samsung_keypad_probe(struct platform_device *pdev) keypad->irq = platform_get_irq(pdev, 0); if (keypad->irq < 0) { error = keypad->irq; - goto err_unprepare_clk; + return error; } error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL, @@ -419,16 +416,19 @@ static int samsung_keypad_probe(struct platform_device *pdev) dev_name(&pdev->dev), keypad); if (error) { dev_err(&pdev->dev, "failed to register keypad interrupt\n"); - goto err_unprepare_clk; + return error; } device_init_wakeup(&pdev->dev, pdata->wakeup); platform_set_drvdata(pdev, keypad); - pm_runtime_enable(&pdev->dev); + + error = devm_pm_runtime_enable(&pdev->dev); + if (error) + return error; error = input_register_device(keypad->input_dev); if (error) - goto err_disable_runtime_pm; + return error; if (pdev->dev.of_node) { devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap); @@ -436,23 +436,6 @@ static int samsung_keypad_probe(struct platform_device *pdev) devm_kfree(&pdev->dev, (void *)pdata); } return 0; - -err_disable_runtime_pm: - pm_runtime_disable(&pdev->dev); -err_unprepare_clk: - clk_unprepare(keypad->clk); - return error; -} - -static void samsung_keypad_remove(struct platform_device *pdev) -{ - struct samsung_keypad *keypad = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - - input_unregister_device(keypad->input_dev); - - clk_unprepare(keypad->clk); } static int samsung_keypad_runtime_suspend(struct device *dev) @@ -528,15 +511,13 @@ static int samsung_keypad_suspend(struct device *dev) struct samsung_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) samsung_keypad_stop(keypad); samsung_keypad_toggle_wakeup(keypad, true); - mutex_unlock(&input_dev->mutex); - return 0; } @@ -546,15 +527,13 @@ static int samsung_keypad_resume(struct device *dev) struct samsung_keypad *keypad = platform_get_drvdata(pdev); struct input_dev *input_dev = keypad->input_dev; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); samsung_keypad_toggle_wakeup(keypad, false); if (input_device_enabled(input_dev)) samsung_keypad_start(keypad); - mutex_unlock(&input_dev->mutex); - return 0; } @@ -564,11 +543,24 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = { samsung_keypad_runtime_resume, NULL) }; +static const struct samsung_chip_info samsung_s3c6410_chip_info = { + .column_shift = 0, +}; + +static const struct samsung_chip_info samsung_s5pv210_chip_info = { + .column_shift = 8, +}; + #ifdef CONFIG_OF static const struct of_device_id samsung_keypad_dt_match[] = { - { .compatible = "samsung,s3c6410-keypad" }, - { .compatible = "samsung,s5pv210-keypad" }, - {}, + { + .compatible = "samsung,s3c6410-keypad", + .data = &samsung_s3c6410_chip_info, + }, { + .compatible = "samsung,s5pv210-keypad", + .data = &samsung_s5pv210_chip_info, + }, + { } }; MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); #endif @@ -576,18 +568,17 @@ MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match); static const struct platform_device_id samsung_keypad_driver_ids[] = { { .name = "samsung-keypad", - .driver_data = KEYPAD_TYPE_SAMSUNG, + .driver_data = (kernel_ulong_t)&samsung_s3c6410_chip_info, }, { .name = "s5pv210-keypad", - .driver_data = KEYPAD_TYPE_S5PV210, + .driver_data = (kernel_ulong_t)&samsung_s5pv210_chip_info, }, - { }, + { } }; MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids); static struct platform_driver samsung_keypad_driver = { .probe = samsung_keypad_probe, - .remove = samsung_keypad_remove, .driver = { .name = "samsung-keypad", .of_match_table = of_match_ptr(samsung_keypad_dt_match), diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c index 159f41eedd41..6937f3576c05 100644 --- a/drivers/input/keyboard/sh_keysc.c +++ b/drivers/input/keyboard/sh_keysc.c @@ -184,7 +184,7 @@ static int sh_keysc_probe(struct platform_device *pdev) if (irq < 0) goto err0; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (priv == NULL) { dev_err(&pdev->dev, "failed to allocate driver data\n"); error = -ENOMEM; diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c index f7b5f1e25c80..954055aaf6e2 100644 --- a/drivers/input/keyboard/snvs_pwrkey.c +++ b/drivers/input/keyboard/snvs_pwrkey.c @@ -27,6 +27,8 @@ #define SNVS_HPSR_BTN BIT(6) #define SNVS_LPSR_SPO BIT(18) #define SNVS_LPCR_DEP_EN BIT(5) +#define SNVS_LPCR_BPT_SHIFT 16 +#define SNVS_LPCR_BPT_MASK (3 << SNVS_LPCR_BPT_SHIFT) #define DEBOUNCE_TIME 30 #define REPEAT_INTERVAL 60 @@ -44,7 +46,8 @@ struct pwrkey_drv_data { static void imx_imx_snvs_check_for_events(struct timer_list *t) { - struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer); + struct pwrkey_drv_data *pdata = timer_container_of(pdata, t, + check_timer); struct input_dev *input = pdata->input; u32 state; @@ -104,7 +107,7 @@ static void imx_snvs_pwrkey_act(void *pdata) { struct pwrkey_drv_data *pd = pdata; - del_timer_sync(&pd->check_timer); + timer_delete_sync(&pd->check_timer); } static int imx_snvs_pwrkey_probe(struct platform_device *pdev) @@ -114,6 +117,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) struct device_node *np; struct clk *clk; int error; + unsigned int val; + unsigned int bpt; u32 vid; /* Get SNVS register Page */ @@ -148,6 +153,27 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev) if (pdata->irq < 0) return -EINVAL; + error = of_property_read_u32(np, "power-off-time-sec", &val); + if (!error) { + switch (val) { + case 0: + bpt = 0x3; + break; + case 5: + case 10: + case 15: + bpt = (val / 5) - 1; + break; + default: + dev_err(&pdev->dev, + "power-off-time-sec %d out of range\n", val); + return -EINVAL; + } + + regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_BPT_MASK, + bpt << SNVS_LPCR_BPT_SHIFT); + } + regmap_read(pdata->snvs, SNVS_HPVIDR1_REG, &vid); pdata->minor_rev = vid & 0xff; diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c index 2fae337562a2..53f3ac64c980 100644 --- a/drivers/input/keyboard/spear-keyboard.c +++ b/drivers/input/keyboard/spear-keyboard.c @@ -14,6 +14,7 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/input.h> +#include <linux/input/matrix_keypad.h> #include <linux/io.h> #include <linux/irq.h> #include <linux/kernel.h> @@ -22,7 +23,6 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/platform_data/keyboard-spear.h> /* Keyboard Registers */ #define MODE_CTL_REG 0x00 @@ -56,13 +56,12 @@ struct spear_kbd { void __iomem *io_base; struct clk *clk; unsigned int irq; - unsigned int mode; - unsigned int suspended_rate; + u32 mode; + u32 suspended_rate; + u32 mode_ctl_reg; unsigned short last_key; unsigned short keycodes[NUM_ROWS * NUM_COLS]; - bool rep; bool irq_wake_enabled; - u32 mode_ctl_reg; }; static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id) @@ -143,46 +142,8 @@ static void spear_kbd_close(struct input_dev *dev) kbd->last_key = KEY_RESERVED; } -#ifdef CONFIG_OF -static int spear_kbd_parse_dt(struct platform_device *pdev, - struct spear_kbd *kbd) -{ - struct device_node *np = pdev->dev.of_node; - int error; - u32 val, suspended_rate; - - if (!np) { - dev_err(&pdev->dev, "Missing DT data\n"); - return -EINVAL; - } - - if (of_property_read_bool(np, "autorepeat")) - kbd->rep = true; - - if (of_property_read_u32(np, "suspended_rate", &suspended_rate)) - kbd->suspended_rate = suspended_rate; - - error = of_property_read_u32(np, "st,mode", &val); - if (error) { - dev_err(&pdev->dev, "DT: Invalid or missing mode\n"); - return error; - } - - kbd->mode = val; - return 0; -} -#else -static inline int spear_kbd_parse_dt(struct platform_device *pdev, - struct spear_kbd *kbd) -{ - return -ENOSYS; -} -#endif - static int spear_kbd_probe(struct platform_device *pdev) { - struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev); - const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL; struct spear_kbd *kbd; struct input_dev *input_dev; int irq; @@ -198,6 +159,14 @@ static int spear_kbd_probe(struct platform_device *pdev) return -ENOMEM; } + error = device_property_read_u32(&pdev->dev, "st,mode", &kbd->mode); + if (error) { + dev_err(&pdev->dev, "Invalid or missing mode\n"); + return error; + } + + device_property_read_u32(&pdev->dev, "suspended_rate", &kbd->suspended_rate); + input_dev = devm_input_allocate_device(&pdev->dev); if (!input_dev) { dev_err(&pdev->dev, "unable to allocate input device\n"); @@ -207,16 +176,6 @@ static int spear_kbd_probe(struct platform_device *pdev) kbd->input = input_dev; kbd->irq = irq; - if (!pdata) { - error = spear_kbd_parse_dt(pdev, kbd); - if (error) - return error; - } else { - kbd->mode = pdata->mode; - kbd->rep = pdata->rep; - kbd->suspended_rate = pdata->suspended_rate; - } - kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(kbd->io_base)) return PTR_ERR(kbd->io_base); @@ -234,21 +193,21 @@ static int spear_kbd_probe(struct platform_device *pdev) input_dev->open = spear_kbd_open; input_dev->close = spear_kbd_close; - error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS, + error = matrix_keypad_build_keymap(NULL, NULL, NUM_ROWS, NUM_COLS, kbd->keycodes, input_dev); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); return error; } - if (kbd->rep) + if (device_property_read_bool(&pdev->dev, "autorepeat")) __set_bit(EV_REP, input_dev->evbit); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_set_drvdata(input_dev, kbd); error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0, - "keyboard", kbd); + "keyboard", kbd); if (error) { dev_err(&pdev->dev, "request_irq failed\n"); return error; diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c index 7ef0b3f4f549..eade05542ed6 100644 --- a/drivers/input/keyboard/stowaway.c +++ b/drivers/input/keyboard/stowaway.c @@ -72,7 +72,7 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - skbd = kzalloc(sizeof(*skbd), GFP_KERNEL); + skbd = kzalloc_obj(*skbd); input_dev = input_allocate_device(); if (!skbd || !input_dev) goto fail1; diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 3299e1919b37..5a0020827047 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -262,7 +262,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - sunkbd = kzalloc(sizeof(*sunkbd), GFP_KERNEL); + sunkbd = kzalloc_obj(*sunkbd); input_dev = input_allocate_device(); if (!sunkbd || !input_dev) goto fail1; diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c deleted file mode 100644 index fbc674d7b9f0..000000000000 --- a/drivers/input/keyboard/tca6416-keypad.c +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for keys on TCA6416 I2C IO expander - * - * Copyright (C) 2010 Texas Instruments - * - * Author : Sriramakrishnan.A.G. <srk@ti.com> - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/i2c.h> -#include <linux/input.h> -#include <linux/tca6416_keypad.h> - -#define TCA6416_INPUT 0 -#define TCA6416_OUTPUT 1 -#define TCA6416_INVERT 2 -#define TCA6416_DIRECTION 3 - -#define TCA6416_POLL_INTERVAL 100 /* msec */ - -static const struct i2c_device_id tca6416_id[] = { - { "tca6416-keys", 16, }, - { "tca6408-keys", 8, }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tca6416_id); - -struct tca6416_keypad_chip { - uint16_t reg_output; - uint16_t reg_direction; - uint16_t reg_input; - - struct i2c_client *client; - struct input_dev *input; - int io_size; - u16 pinmask; - bool use_polling; - struct tca6416_button buttons[]; -}; - -static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val) -{ - int error; - - error = chip->io_size > 8 ? - i2c_smbus_write_word_data(chip->client, reg << 1, val) : - i2c_smbus_write_byte_data(chip->client, reg, val); - if (error < 0) { - dev_err(&chip->client->dev, - "%s failed, reg: %d, val: %d, error: %d\n", - __func__, reg, val, error); - return error; - } - - return 0; -} - -static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) -{ - int retval; - - retval = chip->io_size > 8 ? - i2c_smbus_read_word_data(chip->client, reg << 1) : - i2c_smbus_read_byte_data(chip->client, reg); - if (retval < 0) { - dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n", - __func__, reg, retval); - return retval; - } - - *val = (u16)retval; - return 0; -} - -static void tca6416_keys_scan(struct input_dev *input) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(input); - u16 reg_val, val; - int error, i, pin_index; - - error = tca6416_read_reg(chip, TCA6416_INPUT, ®_val); - if (error) - return; - - reg_val &= chip->pinmask; - - /* Figure out which lines have changed */ - val = reg_val ^ chip->reg_input; - chip->reg_input = reg_val; - - for (i = 0, pin_index = 0; i < 16; i++) { - if (val & (1 << i)) { - struct tca6416_button *button = &chip->buttons[pin_index]; - unsigned int type = button->type ?: EV_KEY; - int state = ((reg_val & (1 << i)) ? 1 : 0) - ^ button->active_low; - - input_event(input, type, button->code, !!state); - input_sync(input); - } - - if (chip->pinmask & (1 << i)) - pin_index++; - } -} - -/* - * This is threaded IRQ handler and this can (and will) sleep. - */ -static irqreturn_t tca6416_keys_isr(int irq, void *dev_id) -{ - tca6416_keys_scan(dev_id); - - return IRQ_HANDLED; -} - -static int tca6416_keys_open(struct input_dev *dev) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - - if (!chip->use_polling) { - /* Get initial device state in case it has switches */ - tca6416_keys_scan(dev); - enable_irq(chip->client->irq); - } - - return 0; -} - -static void tca6416_keys_close(struct input_dev *dev) -{ - struct tca6416_keypad_chip *chip = input_get_drvdata(dev); - - if (!chip->use_polling) - disable_irq(chip->client->irq); -} - -static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) -{ - int error; - - error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); - if (error) - return error; - - /* ensure that keypad pins are set to input */ - error = tca6416_write_reg(chip, TCA6416_DIRECTION, - chip->reg_direction | chip->pinmask); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); - if (error) - return error; - - error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input); - if (error) - return error; - - chip->reg_input &= chip->pinmask; - - return 0; -} - -static int tca6416_keypad_probe(struct i2c_client *client) -{ - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct tca6416_keys_platform_data *pdata; - struct tca6416_keypad_chip *chip; - struct input_dev *input; - int error; - int i; - - /* Check functionality */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { - dev_err(&client->dev, "%s adapter not supported\n", - dev_driver_string(&client->adapter->dev)); - return -ENODEV; - } - - pdata = dev_get_platdata(&client->dev); - if (!pdata) { - dev_dbg(&client->dev, "no platform data\n"); - return -EINVAL; - } - - chip = devm_kzalloc(&client->dev, - struct_size(chip, buttons, pdata->nbuttons), - GFP_KERNEL); - if (!chip) - return -ENOMEM; - - input = devm_input_allocate_device(&client->dev); - if (!input) - return -ENOMEM; - - chip->client = client; - chip->input = input; - chip->io_size = id->driver_data; - chip->pinmask = pdata->pinmask; - chip->use_polling = pdata->use_polling; - - input->phys = "tca6416-keys/input0"; - input->name = client->name; - - input->open = tca6416_keys_open; - input->close = tca6416_keys_close; - - input->id.bustype = BUS_HOST; - input->id.vendor = 0x0001; - input->id.product = 0x0001; - input->id.version = 0x0100; - - /* Enable auto repeat feature of Linux input subsystem */ - if (pdata->rep) - __set_bit(EV_REP, input->evbit); - - for (i = 0; i < pdata->nbuttons; i++) { - unsigned int type; - - chip->buttons[i] = pdata->buttons[i]; - type = (pdata->buttons[i].type) ?: EV_KEY; - input_set_capability(input, type, pdata->buttons[i].code); - } - - input_set_drvdata(input, chip); - - /* - * Initialize cached registers from their original values. - * we can't share this chip with another i2c master. - */ - error = tca6416_setup_registers(chip); - if (error) - return error; - - if (chip->use_polling) { - error = input_setup_polling(input, tca6416_keys_scan); - if (error) { - dev_err(&client->dev, "Failed to setup polling\n"); - return error; - } - - input_set_poll_interval(input, TCA6416_POLL_INTERVAL); - } else { - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, tca6416_keys_isr, - IRQF_TRIGGER_FALLING | - IRQF_ONESHOT | - IRQF_NO_AUTOEN, - "tca6416-keypad", input); - if (error) { - dev_dbg(&client->dev, - "Unable to claim irq %d; error %d\n", - client->irq, error); - return error; - } - } - - error = input_register_device(input); - if (error) { - dev_dbg(&client->dev, - "Unable to register input device, error: %d\n", error); - return error; - } - - i2c_set_clientdata(client, chip); - - return 0; -} - -static struct i2c_driver tca6416_keypad_driver = { - .driver = { - .name = "tca6416-keypad", - }, - .probe = tca6416_keypad_probe, - .id_table = tca6416_id, -}; - -static int __init tca6416_keypad_init(void) -{ - return i2c_add_driver(&tca6416_keypad_driver); -} - -subsys_initcall(tca6416_keypad_init); - -static void __exit tca6416_keypad_exit(void) -{ - i2c_del_driver(&tca6416_keypad_driver); -} -module_exit(tca6416_keypad_exit); - -MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>"); -MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander"); -MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 76fc19ffe21d..68c0afafee7b 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -373,18 +373,7 @@ static struct i2c_driver tca8418_keypad_driver = { .probe = tca8418_keypad_probe, .id_table = tca8418_id, }; - -static int __init tca8418_keypad_init(void) -{ - return i2c_add_driver(&tca8418_keypad_driver); -} -subsys_initcall(tca8418_keypad_init); - -static void __exit tca8418_keypad_exit(void) -{ - i2c_del_driver(&tca8418_keypad_driver); -} -module_exit(tca8418_keypad_exit); +module_i2c_driver(tca8418_keypad_driver); MODULE_AUTHOR("Kyle Manna <kyle.manna@fuel7.com>"); MODULE_DESCRIPTION("Keypad driver for TCA8418"); diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 6776dd94ce76..bc1c80a456f2 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -240,7 +240,7 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable) static void tegra_kbc_keypress_timer(struct timer_list *t) { - struct tegra_kbc *kbc = from_timer(kbc, t, timer); + struct tegra_kbc *kbc = timer_container_of(kbc, t, timer); u32 val; unsigned int i; @@ -416,7 +416,7 @@ static void tegra_kbc_stop(struct tegra_kbc *kbc) } disable_irq(kbc->irq); - del_timer_sync(&kbc->timer); + timer_delete_sync(&kbc->timer); clk_disable_unprepare(kbc->clk); } @@ -703,7 +703,7 @@ static int tegra_kbc_suspend(struct device *dev) if (device_may_wakeup(&pdev->dev)) { disable_irq(kbc->irq); - del_timer_sync(&kbc->timer); + timer_delete_sync(&kbc->timer); tegra_kbc_set_fifo_interrupt(kbc, false); /* Forcefully clear the interrupt status */ diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c index 77e0743a3cf8..5e3d17c5dc9b 100644 --- a/drivers/input/keyboard/twl4030_keypad.c +++ b/drivers/input/keyboard/twl4030_keypad.c @@ -28,10 +28,6 @@ * an internal state machine that decodes pressed keys, including * multi-key combinations. * - * This driver lets boards define what keycodes they wish to report for - * which scancodes, as part of the "struct twl4030_keypad_data" used in - * the probe() routine. - * * See the TPS65950 documentation; that's the general availability * version of the TWL5030 second generation part. */ @@ -47,7 +43,6 @@ struct twl4030_keypad { unsigned short keymap[TWL4030_KEYMAP_SIZE]; u16 kp_state[TWL4030_MAX_ROWS]; - bool autorepeat; unsigned int n_rows; unsigned int n_cols; int irq; @@ -322,8 +317,6 @@ static int twl4030_kp_program(struct twl4030_keypad *kp) */ static int twl4030_kp_probe(struct platform_device *pdev) { - struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev); - const struct matrix_keymap_data *keymap_data = NULL; struct twl4030_keypad *kp; struct input_dev *input; u8 reg; @@ -350,24 +343,10 @@ static int twl4030_kp_probe(struct platform_device *pdev) input->id.product = 0x0001; input->id.version = 0x0003; - if (pdata) { - if (!pdata->rows || !pdata->cols || !pdata->keymap_data) { - dev_err(&pdev->dev, "Missing platform_data\n"); - return -EINVAL; - } - - kp->n_rows = pdata->rows; - kp->n_cols = pdata->cols; - kp->autorepeat = pdata->rep; - keymap_data = pdata->keymap_data; - } else { - error = matrix_keypad_parse_properties(&pdev->dev, &kp->n_rows, - &kp->n_cols); - if (error) - return error; - - kp->autorepeat = true; - } + error = matrix_keypad_parse_properties(&pdev->dev, + &kp->n_rows, &kp->n_cols); + if (error) + return error; if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) { dev_err(&pdev->dev, @@ -379,7 +358,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) if (kp->irq < 0) return kp->irq; - error = matrix_keypad_build_keymap(keymap_data, NULL, + error = matrix_keypad_build_keymap(NULL, NULL, TWL4030_MAX_ROWS, 1 << TWL4030_ROW_SHIFT, kp->keymap, input); @@ -389,9 +368,7 @@ static int twl4030_kp_probe(struct platform_device *pdev) } input_set_capability(input, EV_MSC, MSC_SCAN); - /* Enable auto repeat feature of Linux input subsystem */ - if (kp->autorepeat) - __set_bit(EV_REP, input->evbit); + __set_bit(EV_REP, input->evbit); error = input_register_device(input); if (error) { diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index befa713268ae..c0b4978a8cd5 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -70,7 +70,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv) int err = -ENOMEM; int i; - xtkbd = kmalloc(sizeof(*xtkbd), GFP_KERNEL); + xtkbd = kmalloc_obj(*xtkbd); input_dev = input_allocate_device(); if (!xtkbd || !input_dev) goto fail1; diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c index 9159b5fec129..fee28e537898 100644 --- a/drivers/input/misc/88pm80x_onkey.c +++ b/drivers/input/misc/88pm80x_onkey.c @@ -57,7 +57,7 @@ static int pm80x_onkey_probe(struct platform_device *pdev) struct pm80x_onkey_info *info; int err; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (!info) return -ENOMEM; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 13d135257e06..94a753fcb64f 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -126,6 +126,17 @@ config INPUT_ATMEL_CAPTOUCH To compile this driver as a module, choose M here: the module will be called atmel_captouch. +config INPUT_AW86927 + tristate "Awinic AW86927 Haptic Driver Support" + depends on I2C && INPUT + select INPUT_FF_MEMLESS + select REGMAP_I2C + help + Say Y here if you have an Awinic AW86927 haptic chip. + + To compile this driver as a module, choose M here: the + module will be called aw86927. + config INPUT_BBNSM_PWRKEY tristate "NXP BBNSM Power Key Driver" depends on ARCH_MXC || COMPILE_TEST @@ -179,6 +190,17 @@ config INPUT_PCSPKR To compile this driver as a module, choose M here: the module will be called pcspkr. +config INPUT_PF1550_ONKEY + tristate "NXP PF1550 Onkey support" + depends on MFD_PF1550 + help + Say Y here if you want support for PF1550 PMIC. Onkey can trigger + release and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press + detect. + + To compile this driver as a module, choose M here. The module will be + called pf1550-onkey. + config INPUT_PM8941_PWRKEY tristate "Qualcomm PM8941 power key support" depends on MFD_SPMI_PMIC @@ -230,6 +252,16 @@ config INPUT_M68K_BEEP tristate "M68k Beeper support" depends on M68K +config INPUT_MAX7360_ROTARY + tristate "Maxim MAX7360 Rotary Encoder" + depends on MFD_MAX7360 + help + If you say yes here you get support for the rotary encoder on the + Maxim MAX7360 I/O Expander. + + To compile this driver as a module, choose M here: the module will be + called max7360_rotary. + config INPUT_MAX77650_ONKEY tristate "Maxim MAX77650 ONKEY support" depends on MFD_MAX77650 @@ -240,12 +272,12 @@ config INPUT_MAX77650_ONKEY will be called max77650-onkey. config INPUT_MAX77693_HAPTIC - tristate "MAXIM MAX77693/MAX77843 haptic controller support" - depends on (MFD_MAX77693 || MFD_MAX77843) && PWM + tristate "MAXIM MAX77693/MAX77705/MAX77843 haptic controller support" + depends on (MFD_MAX77693 || MFD_MAX77705 || MFD_MAX77843) && PWM select INPUT_FF_MEMLESS help This option enables support for the haptic controller on - MAXIM MAX77693 and MAX77843 chips. + MAXIM MAX77693, MAX77705 and MAX77843 chips. To compile this driver as module, choose M here: the module will be called max77693-haptic. @@ -506,6 +538,16 @@ config INPUT_TPS65219_PWRBUTTON To compile this driver as a module, choose M here. The module will be called tps65219-pwrbutton. +config INPUT_TPS6594_PWRBUTTON + tristate "TPS6594 Power button driver" + depends on MFD_TPS6594 + help + Say Y here if you want to enable power button reporting for + TPS6594 Power Management IC devices. + + To compile this driver as a module, choose M here. The module will + be called tps6594-pwrbutton. + config INPUT_AXP20X_PEK tristate "X-Powers AXP20X power button driver" depends on MFD_AXP20X @@ -584,13 +626,6 @@ config INPUT_PALMAS_PWRBUTTON To compile this driver as a module, choose M here. The module will be called palmas_pwrbutton. -config INPUT_PCF50633_PMU - tristate "PCF50633 PMU events" - depends on MFD_PCF50633 - help - Say Y to include support for delivering PMU events via input - layer on NXP PCF50633. - config INPUT_PCF8574 tristate "PCF8574 Keypad input device" depends on I2C diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 6d91804d0a6f..415fc4e2918b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o +obj-$(CONFIG_INPUT_AW86927) += aw86927.o obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o @@ -51,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o +obj-$(CONFIG_INPUT_MAX7360_ROTARY) += max7360-rotary.o obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o @@ -59,9 +61,9 @@ obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o obj-$(CONFIG_INPUT_MMA8450) += mma8450.o obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o -obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o +obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o @@ -84,6 +86,7 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TPS65219_PWRBUTTON) += tps65219-pwrbutton.o +obj-$(CONFIG_INPUT_TPS6594_PWRBUTTON) += tps6594-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c index d106f37df6bc..c9fa789337ba 100644 --- a/drivers/input/misc/ad714x.c +++ b/drivers/input/misc/ad714x.c @@ -6,6 +6,7 @@ */ #include <linux/device.h> +#include <linux/export.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/slab.h> diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index c05d898898e8..5ea0ce42a507 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -77,11 +77,8 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = { static int adxl34x_i2c_probe(struct i2c_client *client) { struct adxl34x *ac; - int error; - error = i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA); - if (!error) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); return -EIO; } diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index 7cafbf8d5f1a..ac7674647c09 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -9,6 +9,7 @@ #include <linux/device.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/irq.h> diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 5fa1c9438a85..bb1544d63c51 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -34,8 +34,6 @@ static void arizona_haptics_work(struct work_struct *work) struct arizona_haptics, work); struct arizona *arizona = haptics->arizona; - struct snd_soc_component *component = - snd_soc_dapm_to_component(arizona->dapm); int ret; if (!haptics->arizona->dapm) { @@ -65,7 +63,7 @@ static void arizona_haptics_work(struct work_struct *work) return; } - ret = snd_soc_component_enable_pin(component, "HAPTICS"); + ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to start HAPTICS: %d\n", ret); @@ -80,7 +78,7 @@ static void arizona_haptics_work(struct work_struct *work) } } else { /* This disable sequence will be a noop if already enabled */ - ret = snd_soc_component_disable_pin(component, "HAPTICS"); + ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n", ret); @@ -139,14 +137,12 @@ static int arizona_haptics_play(struct input_dev *input, void *data, static void arizona_haptics_close(struct input_dev *input) { struct arizona_haptics *haptics = input_get_drvdata(input); - struct snd_soc_component *component; + struct snd_soc_dapm_context *dapm = haptics->arizona->dapm; cancel_work_sync(&haptics->work); - if (haptics->arizona->dapm) { - component = snd_soc_dapm_to_component(haptics->arizona->dapm); - snd_soc_component_disable_pin(component, "HAPTICS"); - } + if (dapm) + snd_soc_dapm_disable_pin(dapm, "HAPTICS"); } static int arizona_haptics_probe(struct platform_device *pdev) diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index e84649af801d..8db2dca84975 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -772,7 +772,7 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d if (alt->desc.bInterfaceNumber) return -ENODEV; - ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL); + ar2 = kzalloc_obj(struct ati_remote2); if (!ar2) return -ENOMEM; diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 5b9be2957746..835ad45a9d65 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -14,6 +14,7 @@ #include <linux/input.h> #include <linux/types.h> #include <linux/acpi.h> +#include <linux/platform_device.h> #include <linux/uaccess.h> #define ACPI_ATLAS_NAME "Atlas ACPI" @@ -57,12 +58,17 @@ static acpi_status acpi_atlas_button_handler(u32 function, return status; } -static int atlas_acpi_button_add(struct acpi_device *device) +static int atlas_acpi_button_probe(struct platform_device *pdev) { + struct acpi_device *device; acpi_status status; int i; int err; + device = ACPI_COMPANION(&pdev->dev); + if (!device) + return -ENODEV; + input_dev = input_allocate_device(); if (!input_dev) { pr_err("unable to allocate input device\n"); @@ -106,8 +112,9 @@ static int atlas_acpi_button_add(struct acpi_device *device) return err; } -static void atlas_acpi_button_remove(struct acpi_device *device) +static void atlas_acpi_button_remove(struct platform_device *pdev) { + struct acpi_device *device = ACPI_COMPANION(&pdev->dev); acpi_status status; status = acpi_remove_address_space_handler(device->handle, @@ -124,16 +131,15 @@ static const struct acpi_device_id atlas_device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, atlas_device_ids); -static struct acpi_driver atlas_acpi_driver = { - .name = ACPI_ATLAS_NAME, - .class = ACPI_ATLAS_CLASS, - .ids = atlas_device_ids, - .ops = { - .add = atlas_acpi_button_add, - .remove = atlas_acpi_button_remove, +static struct platform_driver atlas_acpi_driver = { + .probe = atlas_acpi_button_probe, + .remove = atlas_acpi_button_remove, + .driver = { + .name = ACPI_ATLAS_NAME, + .acpi_match_table = atlas_device_ids, }, }; -module_acpi_driver(atlas_acpi_driver); +module_platform_driver(atlas_acpi_driver); MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c new file mode 100644 index 000000000000..f53b8f004cb3 --- /dev/null +++ b/drivers/input/misc/aw86927.c @@ -0,0 +1,882 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Griffin Kroah-Hartman <griffin.kroah@fairphone.com> + * + * Partially based on vendor driver: + * Copyright (c) 2021 AWINIC Technology CO., LTD + * + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> + +#define AW86927_RSTCFG_REG 0x00 +#define AW86927_RSTCFG_SOFTRST 0xaa + +#define AW86927_SYSINT_REG 0x02 +#define AW86927_SYSINT_BST_SCPI BIT(7) +#define AW86927_SYSINT_BST_OVPI BIT(6) +#define AW86927_SYSINT_UVLI BIT(5) +#define AW86927_SYSINT_FF_AEI BIT(4) +#define AW86927_SYSINT_FF_AFI BIT(3) +#define AW86927_SYSINT_OCDI BIT(2) +#define AW86927_SYSINT_OTI BIT(1) +#define AW86927_SYSINT_DONEI BIT(0) + +#define AW86927_SYSINTM_REG 0x03 +#define AW86927_SYSINTM_BST_OVPM BIT(6) +#define AW86927_SYSINTM_FF_AEM BIT(4) +#define AW86927_SYSINTM_FF_AFM BIT(3) +#define AW86927_SYSINTM_DONEM BIT(0) + +#define AW86927_PLAYCFG1_REG 0x06 +#define AW86927_PLAYCFG1_BST_MODE_MASK GENMASK(7, 7) +#define AW86927_PLAYCFG1_BST_MODE_BYPASS 0 +#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0) +#define AW86927_PLAYCFG1_BST_8500MV 0x50 + +#define AW86938_PLAYCFG1_REG 0x06 +#define AW86938_PLAYCFG1_BST_MODE_MASK GENMASK(5, 5) +#define AW86938_PLAYCFG1_BST_MODE_BYPASS 0 +#define AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(4, 0) +#define AW86938_PLAYCFG1_BST_7000MV 0x11 + +#define AW86927_PLAYCFG2_REG 0x07 + +#define AW86927_PLAYCFG3_REG 0x08 +#define AW86927_PLAYCFG3_AUTO_BST_MASK GENMASK(4, 4) +#define AW86927_PLAYCFG3_AUTO_BST_ENABLE 1 +#define AW86927_PLAYCFG3_AUTO_BST_DISABLE 0 +#define AW86927_PLAYCFG3_PLAY_MODE_MASK GENMASK(1, 0) +#define AW86927_PLAYCFG3_PLAY_MODE_RAM 0 + +#define AW86927_PLAYCFG4_REG 0x09 +#define AW86927_PLAYCFG4_STOP BIT(1) +#define AW86927_PLAYCFG4_GO BIT(0) + +#define AW86927_WAVCFG1_REG 0x0a +#define AW86927_WAVCFG1_WAVSEQ1_MASK GENMASK(6, 0) + +#define AW86927_WAVCFG2_REG 0x0b +#define AW86927_WAVCFG2_WAVSEQ2_MASK GENMASK(6, 0) + +#define AW86927_WAVCFG9_REG 0x12 +#define AW86927_WAVCFG9_SEQ1LOOP_MASK GENMASK(7, 4) +#define AW86927_WAVCFG9_SEQ1LOOP_INFINITELY 0x0f + +#define AW86927_CONTCFG1_REG 0x18 +#define AW86927_CONTCFG1_BRK_BST_MD_MASK GENMASK(6, 6) + +#define AW86927_CONTCFG5_REG 0x1c +#define AW86927_CONTCFG5_BST_BRK_GAIN_MASK GENMASK(7, 4) +#define AW86927_CONTCFG5_BRK_GAIN_MASK GENMASK(3, 0) + +#define AW86927_CONTCFG10_REG 0x21 +#define AW86927_CONTCFG10_BRK_TIME_MASK GENMASK(7, 0) +#define AW86927_CONTCFG10_BRK_TIME_DEFAULT 8 + +#define AW86927_CONTCFG13_REG 0x24 +#define AW86927_CONTCFG13_TSET_MASK GENMASK(7, 4) +#define AW86927_CONTCFG13_BEME_SET_MASK GENMASK(3, 0) + +#define AW86927_BASEADDRH_REG 0x2d +#define AW86927_BASEADDRL_REG 0x2e + +#define AW86927_GLBRD5_REG 0x3f +#define AW86927_GLBRD5_STATE_MASK GENMASK(3, 0) +#define AW86927_GLBRD5_STATE_STANDBY 0 + +#define AW86927_RAMADDRH_REG 0x40 + +#define AW86927_RAMADDRL_REG 0x41 + +#define AW86927_RAMDATA_REG 0x42 + +#define AW86927_SYSCTRL3_REG 0x45 +#define AW86927_SYSCTRL3_STANDBY_MASK GENMASK(5, 5) +#define AW86927_SYSCTRL3_STANDBY_ON 1 +#define AW86927_SYSCTRL3_STANDBY_OFF 0 +#define AW86927_SYSCTRL3_EN_RAMINIT_MASK GENMASK(2, 2) +#define AW86927_SYSCTRL3_EN_RAMINIT_ON 1 +#define AW86927_SYSCTRL3_EN_RAMINIT_OFF 0 + +#define AW86927_SYSCTRL4_REG 0x46 +#define AW86927_SYSCTRL4_WAVDAT_MODE_MASK GENMASK(6, 5) +#define AW86927_SYSCTRL4_WAVDAT_24K 0 +#define AW86927_SYSCTRL4_INT_EDGE_MODE_MASK GENMASK(4, 4) +#define AW86927_SYSCTRL4_INT_EDGE_MODE_POS 0 +#define AW86927_SYSCTRL4_INT_MODE_MASK GENMASK(3, 3) +#define AW86927_SYSCTRL4_INT_MODE_EDGE 1 +#define AW86927_SYSCTRL4_GAIN_BYPASS_MASK GENMASK(0, 0) + +#define AW86927_PWMCFG1_REG 0x48 +#define AW86927_PWMCFG1_PRC_EN_MASK GENMASK(7, 7) +#define AW86927_PWMCFG1_PRC_DISABLE 0 + +#define AW86927_PWMCFG3_REG 0x4a +#define AW86927_PWMCFG3_PR_EN_MASK GENMASK(7, 7) +#define AW86927_PWMCFG3_PRCTIME_MASK GENMASK(6, 0) + +#define AW86927_PWMCFG4_REG 0x4b +#define AW86927_PWMCFG4_PRTIME_MASK GENMASK(7, 0) + +#define AW86927_VBATCTRL_REG 0x4c +#define AW86927_VBATCTRL_VBAT_MODE_MASK GENMASK(6, 6) +#define AW86927_VBATCTRL_VBAT_MODE_SW 0 + +#define AW86927_DETCFG1_REG 0x4d +#define AW86927_DETCFG1_DET_GO_MASK GENMASK(1, 0) +#define AW86927_DETCFG1_DET_GO_DET_SEQ0 1 +#define AW86927_DETCFG1_DET_GO_NA 0 + +#define AW86927_DETCFG2_REG 0x4e +#define AW86927_DETCFG2_DET_SEQ0_MASK GENMASK(6, 3) +#define AW86927_DETCFG2_DET_SEQ0_VBAT 0 +#define AW86927_DETCFG2_D2S_GAIN_MASK GENMASK(2, 0) +#define AW86927_DETCFG2_D2S_GAIN_10 4 + +#define AW86927_CHIPIDH_REG 0x57 +#define AW86927_CHIPIDL_REG 0x58 +#define AW86927_CHIPID 0x9270 +#define AW86938_CHIPID 0x9380 + +#define AW86927_TMCFG_REG 0x5b +#define AW86927_TMCFG_UNLOCK 0x7d +#define AW86927_TMCFG_LOCK 0x00 + +#define AW86927_ANACFG11_REG 0x70 + +#define AW86927_ANACFG12_REG 0x71 +#define AW86927_ANACFG12_BST_SKIP_MASK GENMASK(7, 7) +#define AW86927_ANACFG12_BST_SKIP_SHUTDOWN 1 + +#define AW86927_ANACFG13_REG 0x72 +#define AW86927_ANACFG13_BST_PC_MASK GENMASK(7, 4) +#define AW86927_ANACFG13_BST_PEAKCUR_3P45A 6 + +#define AW86927_ANACFG15_REG 0x74 +#define AW86927_ANACFG15_BST_PEAK_MODE_MASK GENMASK(7, 7) +#define AW86927_ANACFG15_BST_PEAK_BACK 1 + +#define AW86927_ANACFG16_REG 0x75 +#define AW86927_ANACFG16_BST_SRC_MASK GENMASK(4, 4) +#define AW86927_ANACFG16_BST_SRC_3NS 0 + +/* default value of base addr */ +#define AW86927_RAM_BASE_ADDR 0x800 +#define AW86927_BASEADDRH_VAL 0x08 +#define AW86927_BASEADDRL_VAL 0x00 + +enum aw86927_work_mode { + AW86927_STANDBY_MODE, + AW86927_RAM_MODE, +}; + +enum aw86927_model { + AW86927, + AW86938, +}; + +struct aw86927_data { + enum aw86927_model model; + struct work_struct play_work; + struct device *dev; + struct input_dev *input_dev; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + u16 level; +}; + +static const struct regmap_config aw86927_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_NONE, + .max_register = 0x80, +}; + +/* + * Sine wave representing the magnitude of the drive to be used. + * Data is encoded in two's complement. + * round(84 * sin(x / 16.25)) + */ +static const u8 aw86927_waveform[] = { + 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x1a, 0x1f, 0x23, 0x28, 0x2d, 0x31, 0x35, + 0x39, 0x3d, 0x41, 0x44, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x4d, 0x4a, 0x47, + 0x44, 0x41, 0x3d, 0x3a, 0x36, 0x31, 0x2d, 0x28, 0x24, 0x1f, 0x1a, 0x15, + 0x10, 0x0a, 0x05, 0x00, 0xfc, 0xf6, 0xf1, 0xec, 0xe7, 0xe2, 0xdd, 0xd8, + 0xd4, 0xcf, 0xcb, 0xc7, 0xc3, 0xbf, 0xbc, 0xb9, 0xb6, 0xb4, 0xb1, 0xb0, + 0xae, 0xad, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xac, 0xae, 0xaf, 0xb1, + 0xb3, 0xb6, 0xb8, 0xbc, 0xbf, 0xc2, 0xc6, 0xca, 0xce, 0xd3, 0xd7, 0xdc, + 0xe1, 0xe6, 0xeb, 0xf0, 0xf5, 0xfb +}; + +struct aw86927_sram_waveform_header { + u8 version; + __be16 start_address; + __be16 end_address; +} __packed; + +static const struct aw86927_sram_waveform_header sram_waveform_header = { + .version = 0x01, + .start_address = cpu_to_be16(AW86927_RAM_BASE_ADDR + + sizeof(struct aw86927_sram_waveform_header)), + .end_address = cpu_to_be16(AW86927_RAM_BASE_ADDR + + sizeof(struct aw86927_sram_waveform_header) + + ARRAY_SIZE(aw86927_waveform) - 1), +}; + +static int aw86927_wait_enter_standby(struct aw86927_data *haptics) +{ + unsigned int reg_val; + int err; + + err = regmap_read_poll_timeout(haptics->regmap, AW86927_GLBRD5_REG, reg_val, + (FIELD_GET(AW86927_GLBRD5_STATE_MASK, reg_val) == + AW86927_GLBRD5_STATE_STANDBY), + 2500, 2500 * 100); + + if (err) { + dev_err(haptics->dev, "did not enter standby: %d\n", err); + return err; + } + return 0; +} + +static int aw86927_play_mode(struct aw86927_data *haptics, u8 play_mode) +{ + int err; + + switch (play_mode) { + case AW86927_STANDBY_MODE: + /* Briefly toggle standby, then toggle back to standby off */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_STANDBY_MASK, + FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK, + AW86927_SYSCTRL3_STANDBY_ON)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_STANDBY_MASK, + FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK, + AW86927_SYSCTRL3_STANDBY_OFF)); + if (err) + return err; + + break; + + case AW86927_RAM_MODE: + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_PLAY_MODE_MASK, + FIELD_PREP(AW86927_PLAYCFG3_PLAY_MODE_MASK, + AW86927_PLAYCFG3_PLAY_MODE_RAM)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG1_REG, + AW86927_PLAYCFG1_BST_MODE_MASK, + FIELD_PREP(AW86927_PLAYCFG1_BST_MODE_MASK, + AW86927_PLAYCFG1_BST_MODE_BYPASS)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_VBATCTRL_REG, + AW86927_VBATCTRL_VBAT_MODE_MASK, + FIELD_PREP(AW86927_VBATCTRL_VBAT_MODE_MASK, + AW86927_VBATCTRL_VBAT_MODE_SW)); + if (err) + return err; + + break; + } + + return 0; +} + +static int aw86927_stop(struct aw86927_data *haptics) +{ + int err; + + err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_STOP); + if (err) { + dev_err(haptics->dev, "Failed to stop playback: %d\n", err); + return err; + } + + err = aw86927_wait_enter_standby(haptics); + if (err) { + dev_err(haptics->dev, "Failed to enter standby, trying to force it\n"); + err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE); + if (err) + return err; + } + + return 0; +} + +static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct aw86927_data *haptics = input_get_drvdata(dev); + int level; + + level = effect->u.rumble.strong_magnitude; + if (!level) + level = effect->u.rumble.weak_magnitude; + + /* If level does not change, don't restart playback */ + if (haptics->level == level) + return 0; + + haptics->level = level; + + schedule_work(&haptics->play_work); + + return 0; +} + +static int aw86927_play_sine(struct aw86927_data *haptics) +{ + int err; + + err = aw86927_stop(haptics); + if (err) + return err; + + err = aw86927_play_mode(haptics, AW86927_RAM_MODE); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_AUTO_BST_MASK, + FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK, + AW86927_PLAYCFG3_AUTO_BST_ENABLE)); + if (err) + return err; + + /* Set waveseq 1 to the first wave */ + err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG1_REG, + AW86927_WAVCFG1_WAVSEQ1_MASK, + FIELD_PREP(AW86927_WAVCFG1_WAVSEQ1_MASK, 1)); + if (err) + return err; + + /* set wavseq 2 to zero */ + err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG2_REG, + AW86927_WAVCFG2_WAVSEQ2_MASK, + FIELD_PREP(AW86927_WAVCFG2_WAVSEQ2_MASK, 0)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_WAVCFG9_REG, + AW86927_WAVCFG9_SEQ1LOOP_MASK, + FIELD_PREP(AW86927_WAVCFG9_SEQ1LOOP_MASK, + AW86927_WAVCFG9_SEQ1LOOP_INFINITELY)); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, haptics->level * 0x80 / 0xffff); + if (err) + return err; + + /* Start playback */ + err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_GO); + if (err) + return err; + + return 0; +} + +static void aw86927_close(struct input_dev *input) +{ + struct aw86927_data *haptics = input_get_drvdata(input); + struct device *dev = &haptics->client->dev; + int err; + + cancel_work_sync(&haptics->play_work); + + err = aw86927_stop(haptics); + if (err) + dev_err(dev, "Failed to close the Driver: %d\n", err); +} + +static void aw86927_haptics_play_work(struct work_struct *work) +{ + struct aw86927_data *haptics = + container_of(work, struct aw86927_data, play_work); + struct device *dev = &haptics->client->dev; + int err; + + if (haptics->level) + err = aw86927_play_sine(haptics); + else + err = aw86927_stop(haptics); + + if (err) + dev_err(dev, "Failed to execute work command: %d\n", err); +} + +static void aw86927_hw_reset(struct aw86927_data *haptics) +{ + /* Assert reset */ + gpiod_set_value_cansleep(haptics->reset_gpio, 1); + /* Wait ~1ms */ + usleep_range(1000, 2000); + /* Deassert reset */ + gpiod_set_value_cansleep(haptics->reset_gpio, 0); + /* Wait ~8ms until I2C is accessible */ + usleep_range(8000, 8500); +} + +static int aw86927_haptic_init(struct aw86927_data *haptics) +{ + int err; + + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL4_REG, + AW86927_SYSCTRL4_WAVDAT_MODE_MASK, + FIELD_PREP(AW86927_SYSCTRL4_WAVDAT_MODE_MASK, + AW86927_SYSCTRL4_WAVDAT_24K)); + if (err) + return err; + + /* enable gain bypass */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL4_REG, + AW86927_SYSCTRL4_GAIN_BYPASS_MASK, + FIELD_PREP(AW86927_SYSCTRL4_GAIN_BYPASS_MASK, + 0x01)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW86927_ANACFG11_REG, 0x0f); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG12_REG, + AW86927_ANACFG12_BST_SKIP_MASK, + FIELD_PREP(AW86927_ANACFG12_BST_SKIP_MASK, + AW86927_ANACFG12_BST_SKIP_SHUTDOWN)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG15_REG, + AW86927_ANACFG15_BST_PEAK_MODE_MASK, + FIELD_PREP(AW86927_ANACFG15_BST_PEAK_MODE_MASK, + AW86927_ANACFG15_BST_PEAK_BACK)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG16_REG, + AW86927_ANACFG16_BST_SRC_MASK, + FIELD_PREP(AW86927_ANACFG16_BST_SRC_MASK, + AW86927_ANACFG16_BST_SRC_3NS)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_LOCK); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_CONTCFG1_REG, + AW86927_CONTCFG1_BRK_BST_MD_MASK, + FIELD_PREP(AW86927_CONTCFG1_BRK_BST_MD_MASK, 0x00)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_CONTCFG5_REG, + FIELD_PREP(AW86927_CONTCFG5_BST_BRK_GAIN_MASK, 0x05) | + FIELD_PREP(AW86927_CONTCFG5_BRK_GAIN_MASK, 0x08)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW86927_CONTCFG10_REG, + AW86927_CONTCFG10_BRK_TIME_MASK, + FIELD_PREP(AW86927_CONTCFG10_BRK_TIME_MASK, + AW86927_CONTCFG10_BRK_TIME_DEFAULT)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_CONTCFG13_REG, + FIELD_PREP(AW86927_CONTCFG13_TSET_MASK, 0x06) | + FIELD_PREP(AW86927_CONTCFG13_BEME_SET_MASK, 0x02)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG2_REG, + AW86927_DETCFG2_D2S_GAIN_MASK, + FIELD_PREP(AW86927_DETCFG2_D2S_GAIN_MASK, + AW86927_DETCFG2_D2S_GAIN_10)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PWMCFG1_REG, + AW86927_PWMCFG1_PRC_EN_MASK, + FIELD_PREP(AW86927_PWMCFG1_PRC_EN_MASK, + AW86927_PWMCFG1_PRC_DISABLE)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_PWMCFG3_REG, + FIELD_PREP(AW86927_PWMCFG3_PR_EN_MASK, 0x01) | + FIELD_PREP(AW86927_PWMCFG3_PRCTIME_MASK, 0x3f)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_PWMCFG4_REG, + AW86927_PWMCFG4_PRTIME_MASK, + FIELD_PREP(AW86927_PWMCFG4_PRTIME_MASK, 0x32)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_ANACFG13_REG, + AW86927_ANACFG13_BST_PC_MASK, + FIELD_PREP(AW86927_ANACFG13_BST_PC_MASK, + AW86927_ANACFG13_BST_PEAKCUR_3P45A)); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_TMCFG_REG, AW86927_TMCFG_LOCK); + if (err) + return err; + + switch (haptics->model) { + case AW86927: + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG1_REG, + AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK, + FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK, + AW86927_PLAYCFG1_BST_8500MV)); + if (err) + return err; + break; + case AW86938: + err = regmap_update_bits(haptics->regmap, + AW86938_PLAYCFG1_REG, + AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK, + FIELD_PREP(AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK, + AW86938_PLAYCFG1_BST_7000MV)); + if (err) + return err; + break; + } + + err = regmap_update_bits(haptics->regmap, + AW86927_PLAYCFG3_REG, + AW86927_PLAYCFG3_AUTO_BST_MASK, + FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK, + AW86927_PLAYCFG3_AUTO_BST_DISABLE)); + if (err) + return err; + + return 0; +} + +static int aw86927_ram_init(struct aw86927_data *haptics) +{ + int err; + + err = aw86927_wait_enter_standby(haptics); + if (err) + return err; + + /* Enable SRAM init */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_EN_RAMINIT_MASK, + FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK, + AW86927_SYSCTRL3_EN_RAMINIT_ON)); + + /* AW86938 wants a 1ms delay here */ + usleep_range(1000, 1500); + + /* Set base address for the start of the SRAM waveforms */ + err = regmap_write(haptics->regmap, + AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_BASEADDRL_REG, AW86927_BASEADDRL_VAL); + if (err) + return err; + + /* Set start of SRAM, before the data is written it will be the same as the base */ + err = regmap_write(haptics->regmap, + AW86927_RAMADDRH_REG, AW86927_BASEADDRH_VAL); + if (err) + return err; + + err = regmap_write(haptics->regmap, + AW86927_RAMADDRL_REG, AW86927_BASEADDRL_VAL); + if (err) + return err; + + /* Write waveform header to SRAM */ + err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG, + &sram_waveform_header, sizeof(sram_waveform_header)); + if (err) + return err; + + /* Write waveform to SRAM */ + err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG, + aw86927_waveform, ARRAY_SIZE(aw86927_waveform)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG2_REG, + AW86927_DETCFG2_DET_SEQ0_MASK, + FIELD_PREP(AW86927_DETCFG2_DET_SEQ0_MASK, + AW86927_DETCFG2_DET_SEQ0_VBAT)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG1_REG, + AW86927_DETCFG1_DET_GO_MASK, + FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK, + AW86927_DETCFG1_DET_GO_DET_SEQ0)); + if (err) + return err; + + usleep_range(3000, 3500); + + err = regmap_update_bits(haptics->regmap, + AW86927_DETCFG1_REG, + AW86927_DETCFG1_DET_GO_MASK, + FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK, + AW86927_DETCFG1_DET_GO_NA)); + if (err) + return err; + + /* Disable SRAM init */ + err = regmap_update_bits(haptics->regmap, + AW86927_SYSCTRL3_REG, + AW86927_SYSCTRL3_EN_RAMINIT_MASK, + FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK, + AW86927_SYSCTRL3_EN_RAMINIT_OFF)); + if (err) + return err; + + return 0; +} + +static irqreturn_t aw86927_irq(int irq, void *data) +{ + struct aw86927_data *haptics = data; + struct device *dev = &haptics->client->dev; + unsigned int reg_val; + int err; + + err = regmap_read(haptics->regmap, AW86927_SYSINT_REG, ®_val); + if (err) { + dev_err(dev, "Failed to read SYSINT register: %d\n", err); + return IRQ_NONE; + } + + if (reg_val & AW86927_SYSINT_BST_SCPI) + dev_err(dev, "Received a Short Circuit Protection interrupt\n"); + if (reg_val & AW86927_SYSINT_BST_OVPI) + dev_err(dev, "Received an Over Voltage Protection interrupt\n"); + if (reg_val & AW86927_SYSINT_UVLI) + dev_err(dev, "Received an Under Voltage Lock Out interrupt\n"); + if (reg_val & AW86927_SYSINT_OCDI) + dev_err(dev, "Received an Over Current interrupt\n"); + if (reg_val & AW86927_SYSINT_OTI) + dev_err(dev, "Received an Over Temperature interrupt\n"); + + if (reg_val & AW86927_SYSINT_DONEI) + dev_dbg(dev, "Chip playback done!\n"); + if (reg_val & AW86927_SYSINT_FF_AFI) + dev_dbg(dev, "The RTP mode FIFO is almost full!\n"); + if (reg_val & AW86927_SYSINT_FF_AEI) + dev_dbg(dev, "The RTP mode FIFO is almost empty!\n"); + + return IRQ_HANDLED; +} + +static int aw86927_detect(struct aw86927_data *haptics) +{ + __be16 read_buf; + u16 chip_id; + int err; + + err = regmap_bulk_read(haptics->regmap, AW86927_CHIPIDH_REG, &read_buf, 2); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to read CHIPID registers\n"); + + chip_id = be16_to_cpu(read_buf); + + switch (chip_id) { + case AW86927_CHIPID: + haptics->model = AW86927; + break; + case AW86938_CHIPID: + haptics->model = AW86938; + break; + default: + dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id); + return -ENODEV; + } + + return 0; +} + +static int aw86927_probe(struct i2c_client *client) +{ + struct aw86927_data *haptics; + int err; + + haptics = devm_kzalloc(&client->dev, sizeof(struct aw86927_data), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->dev = &client->dev; + haptics->client = client; + + i2c_set_clientdata(client, haptics); + + haptics->regmap = devm_regmap_init_i2c(client, &aw86927_regmap_config); + if (IS_ERR(haptics->regmap)) + return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap), + "Failed to allocate register map\n"); + + haptics->input_dev = devm_input_allocate_device(haptics->dev); + if (!haptics->input_dev) + return -ENOMEM; + + haptics->reset_gpio = devm_gpiod_get(haptics->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(haptics->reset_gpio)) + return dev_err_probe(haptics->dev, PTR_ERR(haptics->reset_gpio), + "Failed to get reset gpio\n"); + + /* Hardware reset */ + aw86927_hw_reset(haptics); + + /* Software reset */ + err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST); + if (err) + return dev_err_probe(haptics->dev, err, "Failed Software reset\n"); + + /* Wait ~3ms until I2C is accessible */ + usleep_range(3000, 3500); + + err = aw86927_detect(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to find chip\n"); + + /* IRQ config */ + err = regmap_write(haptics->regmap, AW86927_SYSCTRL4_REG, + FIELD_PREP(AW86927_SYSCTRL4_INT_MODE_MASK, + AW86927_SYSCTRL4_INT_MODE_EDGE) | + FIELD_PREP(AW86927_SYSCTRL4_INT_EDGE_MODE_MASK, + AW86927_SYSCTRL4_INT_EDGE_MODE_POS)); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to configure interrupt modes\n"); + + err = regmap_write(haptics->regmap, AW86927_SYSINTM_REG, + AW86927_SYSINTM_BST_OVPM | + AW86927_SYSINTM_FF_AEM | + AW86927_SYSINTM_FF_AFM | + AW86927_SYSINTM_DONEM); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to configure interrupt masks\n"); + + err = devm_request_threaded_irq(haptics->dev, client->irq, NULL, + aw86927_irq, IRQF_ONESHOT, NULL, haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to request threaded irq\n"); + + INIT_WORK(&haptics->play_work, aw86927_haptics_play_work); + + haptics->input_dev->name = "aw86927-haptics"; + haptics->input_dev->close = aw86927_close; + + input_set_drvdata(haptics->input_dev, haptics); + input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); + + err = input_ff_create_memless(haptics->input_dev, NULL, aw86927_haptics_play); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to create FF dev\n"); + + /* Set up registers */ + err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE); + if (err) + return dev_err_probe(haptics->dev, err, + "Failed to enter standby for Haptic init\n"); + + err = aw86927_haptic_init(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Haptic init failed\n"); + + /* RAM init, upload the waveform for playback */ + err = aw86927_ram_init(haptics); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to init aw86927 sram\n"); + + err = input_register_device(haptics->input_dev); + if (err) + return dev_err_probe(haptics->dev, err, "Failed to register input device\n"); + + return 0; +} + +static const struct of_device_id aw86927_of_id[] = { + { .compatible = "awinic,aw86927" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, aw86927_of_id); + +static struct i2c_driver aw86927_driver = { + .driver = { + .name = "aw86927-haptics", + .of_match_table = aw86927_of_id, + }, + .probe = aw86927_probe, +}; + +module_i2c_driver(aw86927_driver); + +MODULE_AUTHOR("Griffin Kroah-Hartman <griffin.kroah@fairphone.com>"); +MODULE_DESCRIPTION("AWINIC AW86927 LRA Haptic Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c index 0cfe5d4a573c..353d3c1d347d 100644 --- a/drivers/input/misc/cm109.c +++ b/drivers/input/misc/cm109.c @@ -696,7 +696,7 @@ static int cm109_usb_probe(struct usb_interface *intf, if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc_obj(*dev); if (!dev) return -ENOMEM; @@ -721,7 +721,7 @@ static int cm109_usb_probe(struct usb_interface *intf, if (!dev->ctl_data) goto err_out; - dev->ctl_req = kmalloc(sizeof(*(dev->ctl_req)), GFP_KERNEL); + dev->ctl_req = kmalloc_obj(*(dev->ctl_req)); if (!dev->ctl_req) goto err_out; diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index cfc12332bee1..a641453188d9 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -6,6 +6,7 @@ * Author: Hemanth V <hemanthv@ti.com> */ +#include <linux/export.h> #include <linux/types.h> #include <linux/interrupt.h> #include <linux/delay.h> @@ -284,7 +285,7 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, goto err_out; } - data = kzalloc(sizeof(*data), GFP_KERNEL); + data = kzalloc_obj(*data); input_dev = input_allocate_device(); if (!data || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/misc/cs40l50-vibra.c b/drivers/input/misc/cs40l50-vibra.c index dce3b0ec8cf3..996d6c38cca4 100644 --- a/drivers/input/misc/cs40l50-vibra.c +++ b/drivers/input/misc/cs40l50-vibra.c @@ -238,6 +238,8 @@ static int cs40l50_upload_owt(struct cs40l50_work *work_data) header.data_words = len / sizeof(u32); new_owt_effect_data = kmalloc(sizeof(header) + len, GFP_KERNEL); + if (!new_owt_effect_data) + return -ENOMEM; memcpy(new_owt_effect_data, &header, sizeof(header)); memcpy(new_owt_effect_data + sizeof(header), work_data->custom_data, len); @@ -274,7 +276,7 @@ static void cs40l50_add_worker(struct work_struct *work) /* Update effect if already uploaded, otherwise create new effect */ effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head); if (!effect) { - effect = kzalloc(sizeof(*effect), GFP_KERNEL); + effect = kzalloc_obj(*effect); if (!effect) { error = -ENOMEM; goto err_pm; @@ -306,7 +308,6 @@ err_free: list_add(&effect->list, &vib->effect_head); } err_pm: - pm_runtime_mark_last_busy(vib->dev); pm_runtime_put_autosuspend(vib->dev); err_exit: work_data->error = error; @@ -366,7 +367,6 @@ static void cs40l50_start_worker(struct work_struct *work) dev_err(vib->dev, "Effect to play not found\n"); } - pm_runtime_mark_last_busy(vib->dev); pm_runtime_put_autosuspend(vib->dev); err_free: kfree(work_data); @@ -382,7 +382,6 @@ static void cs40l50_stop_worker(struct work_struct *work) vib->dsp.write(vib->dev, vib->regmap, vib->dsp.stop_cmd); - pm_runtime_mark_last_busy(vib->dev); pm_runtime_put_autosuspend(vib->dev); kfree(work_data); @@ -393,7 +392,7 @@ static int cs40l50_playback(struct input_dev *dev, int effect_id, int val) struct cs40l50_vibra *vib = input_get_drvdata(dev); struct cs40l50_work *work_data; - work_data = kzalloc(sizeof(*work_data), GFP_ATOMIC); + work_data = kzalloc_obj(*work_data, GFP_ATOMIC); if (!work_data) return -ENOMEM; @@ -454,7 +453,6 @@ static void cs40l50_erase_worker(struct work_struct *work) list_del(&erase_effect->list); kfree(erase_effect); err_pm: - pm_runtime_mark_last_busy(vib->dev); pm_runtime_put_autosuspend(vib->dev); err_exit: work_data->error = error; @@ -480,7 +478,6 @@ static int cs40l50_erase(struct input_dev *dev, int effect_id) static void cs40l50_remove_wq(void *data) { - flush_workqueue(data); destroy_workqueue(data); } diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c index cc23625019e3..180b3bc76525 100644 --- a/drivers/input/misc/da9052_onkey.c +++ b/drivers/input/misc/da9052_onkey.c @@ -80,7 +80,7 @@ static int da9052_onkey_probe(struct platform_device *pdev) return -EINVAL; } - onkey = kzalloc(sizeof(*onkey), GFP_KERNEL); + onkey = kzalloc_obj(*onkey); input_dev = input_allocate_device(); if (!onkey || !input_dev) { dev_err(&pdev->dev, "Failed to allocate memory\n"); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 96cd6a078c8a..e2089d6ac850 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -7,14 +7,16 @@ * Copyright: (C) 2014 Texas Instruments, Inc. */ +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/module.h> #include <linux/regmap.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> +#include <linux/slab.h> #include <dt-bindings/input/ti-drv260x.h> @@ -165,6 +167,12 @@ #define DRV260X_AUTOCAL_TIME_500MS (2 << 4) #define DRV260X_AUTOCAL_TIME_1000MS (3 << 4) +/* + * Timeout for waiting for the GO status bit, in seconds. Should be reasonably + * large to wait for a auto-calibration cycle completion. + */ +#define DRV260X_GO_TIMEOUT_S 5 + /** * struct drv260x_data - * @input_dev: Pointer to the input device @@ -308,6 +316,7 @@ static int drv260x_init(struct drv260x_data *haptics) { int error; unsigned int cal_buf; + unsigned long timeout; error = regmap_write(haptics->regmap, DRV260X_RATED_VOLT, haptics->rated_voltage); @@ -397,6 +406,7 @@ static int drv260x_init(struct drv260x_data *haptics) return error; } + timeout = jiffies + DRV260X_GO_TIMEOUT_S * HZ; do { usleep_range(15000, 15500); error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf); @@ -406,6 +416,11 @@ static int drv260x_init(struct drv260x_data *haptics) error); return error; } + if (time_after(jiffies, timeout)) { + dev_err(&haptics->client->dev, + "Calibration timeout. The device cannot be used.\n"); + return -ETIMEDOUT; + } } while (cal_buf == DRV260X_GO_BIT); return 0; @@ -419,6 +434,13 @@ static const struct regmap_config drv260x_regmap_config = { .cache_type = REGCACHE_NONE, }; +static void drv260x_power_off(void *data) +{ + struct drv260x_data *haptics = data; + + regulator_disable(haptics->regulator); +} + static int drv260x_probe(struct i2c_client *client) { struct device *dev = &client->dev; @@ -484,6 +506,16 @@ static int drv260x_probe(struct i2c_client *client) return error; } + error = regulator_enable(haptics->regulator); + if (error) { + dev_err(dev, "Failed to enable regulator: %d\n", error); + return error; + } + + error = devm_add_action_or_reset(dev, drv260x_power_off, haptics); + if (error) + return error; + haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(haptics->enable_gpio)) @@ -598,11 +630,22 @@ static int drv260x_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume); static const struct i2c_device_id drv260x_id[] = { + { "drv2604" }, + { "drv2604l" }, + { "drv2605" }, { "drv2605l" }, { } }; MODULE_DEVICE_TABLE(i2c, drv260x_id); +#ifdef CONFIG_ACPI +static const struct acpi_device_id drv260x_acpi_match[] = { + { "DRV2604" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, drv260x_acpi_match); +#endif + static const struct of_device_id drv260x_of_match[] = { { .compatible = "ti,drv2604", }, { .compatible = "ti,drv2604l", }, @@ -616,6 +659,7 @@ static struct i2c_driver drv260x_driver = { .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", + .acpi_match_table = ACPI_PTR(drv260x_acpi_match), .of_match_table = drv260x_of_match, .pm = pm_sleep_ptr(&drv260x_pm_ops), }, diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c index d2d2954e2f79..3d65cb4f4ef3 100644 --- a/drivers/input/misc/gpio-beeper.c +++ b/drivers/input/misc/gpio-beeper.c @@ -94,7 +94,7 @@ static int gpio_beeper_probe(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id gpio_beeper_of_match[] = { - { .compatible = BEEPER_MODNAME, }, + { .compatible = "gpio-beeper", }, { } }; MODULE_DEVICE_TABLE(of, gpio_beeper_of_match); diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c index ee668eba302f..f0759dd39b35 100644 --- a/drivers/input/misc/gpio_decoder.c +++ b/drivers/input/misc/gpio_decoder.c @@ -6,13 +6,18 @@ * encoded numeric value into an input event. */ -#include <linux/device.h> +#include <linux/bitmap.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/err.h> #include <linux/gpio/consumer.h> #include <linux/input.h> -#include <linux/kernel.h> +#include <linux/minmax.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/types.h> struct gpio_decoder { struct gpio_descs *input_gpios; @@ -24,23 +29,18 @@ struct gpio_decoder { static int gpio_decoder_get_gpios_state(struct gpio_decoder *decoder) { struct gpio_descs *gpios = decoder->input_gpios; - unsigned int ret = 0; - int i, val; - - for (i = 0; i < gpios->ndescs; i++) { - val = gpiod_get_value_cansleep(gpios->desc[i]); - if (val < 0) { - dev_err(decoder->dev, - "Error reading gpio %d: %d\n", - desc_to_gpio(gpios->desc[i]), val); - return val; - } - - val = !!val; - ret = (ret << 1) | val; + DECLARE_BITMAP(values, 32); + unsigned int size; + int err; + + size = min(gpios->ndescs, 32U); + err = gpiod_get_array_value_cansleep(size, gpios->desc, gpios->info, values); + if (err) { + dev_err(decoder->dev, "Error reading GPIO: %d\n", err); + return err; } - return ret; + return bitmap_read(values, 0, size); } static void gpio_decoder_poll_gpios(struct input_dev *input) @@ -61,7 +61,7 @@ static int gpio_decoder_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct gpio_decoder *decoder; struct input_dev *input; - u32 max; + u32 max; int err; decoder = devm_kzalloc(dev, sizeof(*decoder), GFP_KERNEL); @@ -72,18 +72,18 @@ static int gpio_decoder_probe(struct platform_device *pdev) device_property_read_u32(dev, "linux,axis", &decoder->axis); decoder->input_gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); - if (IS_ERR(decoder->input_gpios)) { - dev_err(dev, "unable to acquire input gpios\n"); - return PTR_ERR(decoder->input_gpios); - } + if (IS_ERR(decoder->input_gpios)) + return dev_err_probe(dev, PTR_ERR(decoder->input_gpios), + "unable to acquire input gpios\n"); - if (decoder->input_gpios->ndescs < 2) { - dev_err(dev, "not enough gpios found\n"); - return -EINVAL; - } + if (decoder->input_gpios->ndescs < 2) + return dev_err_probe(dev, -EINVAL, "not enough gpios found\n"); + + if (decoder->input_gpios->ndescs > 31) + return dev_err_probe(dev, -EINVAL, "too many gpios found\n"); if (device_property_read_u32(dev, "decoder-max-value", &max)) - max = (1U << decoder->input_gpios->ndescs) - 1; + max = BIT(decoder->input_gpios->ndescs) - 1; input = devm_input_allocate_device(dev); if (!input) @@ -96,33 +96,27 @@ static int gpio_decoder_probe(struct platform_device *pdev) input_set_abs_params(input, decoder->axis, 0, max, 0, 0); err = input_setup_polling(input, gpio_decoder_poll_gpios); - if (err) { - dev_err(dev, "failed to set up polling\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, "failed to set up polling\n"); err = input_register_device(input); - if (err) { - dev_err(dev, "failed to register input device\n"); - return err; - } + if (err) + return dev_err_probe(dev, err, "failed to register input device\n"); return 0; } -#ifdef CONFIG_OF static const struct of_device_id gpio_decoder_of_match[] = { { .compatible = "gpio-decoder", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, gpio_decoder_of_match); -#endif static struct platform_driver gpio_decoder_driver = { .probe = gpio_decoder_probe, .driver = { .name = "gpio-decoder", - .of_match_table = of_match_ptr(gpio_decoder_of_match), + .of_match_table = gpio_decoder_of_match, } }; module_platform_driver(gpio_decoder_driver); diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c index d3c293a95d32..d315017324d9 100644 --- a/drivers/input/misc/hisi_powerkey.c +++ b/drivers/input/misc/hisi_powerkey.c @@ -30,7 +30,7 @@ static irqreturn_t hi65xx_power_press_isr(int irq, void *q) { struct input_dev *input = q; - pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); + pm_wakeup_dev_event(input->dev.parent, MAX_HELD_TIME, true); input_report_key(input, KEY_POWER, 1); input_sync(input); diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c index d9ee14b1f451..7a1cb9333f53 100644 --- a/drivers/input/misc/ims-pcu.c +++ b/drivers/input/misc/ims-pcu.c @@ -286,7 +286,7 @@ static int ims_pcu_setup_gamepad(struct ims_pcu *pcu) struct input_dev *input; int error; - gamepad = kzalloc(sizeof(*gamepad), GFP_KERNEL); + gamepad = kzalloc_obj(*gamepad); input = input_allocate_device(); if (!gamepad || !input) { dev_err(pcu->dev, @@ -438,6 +438,14 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu) } } +static void ims_pcu_reset_packet(struct ims_pcu *pcu) +{ + pcu->have_stx = true; + pcu->have_dle = false; + pcu->read_pos = 0; + pcu->check_sum = 0; +} + static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) { int i; @@ -450,6 +458,14 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) continue; if (pcu->have_dle) { + if (pcu->read_pos >= IMS_PCU_BUF_SIZE) { + dev_warn(pcu->dev, + "Packet too long (%d bytes), discarding\n", + pcu->read_pos); + ims_pcu_reset_packet(pcu); + continue; + } + pcu->have_dle = false; pcu->read_buf[pcu->read_pos++] = data; pcu->check_sum += data; @@ -462,10 +478,8 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) dev_warn(pcu->dev, "Unexpected STX at byte %d, discarding old data\n", pcu->read_pos); + ims_pcu_reset_packet(pcu); pcu->have_stx = true; - pcu->have_dle = false; - pcu->read_pos = 0; - pcu->check_sum = 0; break; case IMS_PCU_PROTOCOL_DLE: @@ -485,12 +499,18 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb) ims_pcu_handle_response(pcu); } - pcu->have_stx = false; - pcu->have_dle = false; - pcu->read_pos = 0; + ims_pcu_reset_packet(pcu); break; default: + if (pcu->read_pos >= IMS_PCU_BUF_SIZE) { + dev_warn(pcu->dev, + "Packet too long (%d bytes), discarding\n", + pcu->read_pos); + ims_pcu_reset_packet(pcu); + continue; + } + pcu->read_buf[pcu->read_pos++] = data; pcu->check_sum += data; break; @@ -844,6 +864,12 @@ static int ims_pcu_flash_firmware(struct ims_pcu *pcu, addr = be32_to_cpu(rec->addr) / 2; len = be16_to_cpu(rec->len); + if (len > sizeof(pcu->cmd_buf) - 1 - sizeof(*fragment)) { + dev_err(pcu->dev, + "Invalid record length in firmware: %d\n", len); + return -EINVAL; + } + fragment = (void *)&pcu->cmd_buf[1]; put_unaligned_le32(addr, &fragment->addr); fragment->len = len; @@ -1598,7 +1624,7 @@ static void ims_pcu_buffers_free(struct ims_pcu *pcu) usb_kill_urb(pcu->urb_in); usb_free_urb(pcu->urb_in); - usb_free_coherent(pcu->udev, pcu->max_out_size, + usb_free_coherent(pcu->udev, pcu->max_in_size, pcu->urb_in_buf, pcu->read_dma); kfree(pcu->urb_out_buf); @@ -1985,7 +2011,7 @@ static int ims_pcu_probe(struct usb_interface *intf, struct ims_pcu *pcu; int error; - pcu = kzalloc(sizeof(*pcu), GFP_KERNEL); + pcu = kzalloc_obj(*pcu); if (!pcu) return -ENOMEM; diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index 7a6e6927f331..7fba4a8edceb 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -771,7 +771,7 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626, u8 *thresh = &sys_reg->tp_grp_reg.ch_reg_tp[i].thresh; char tc_name[10]; - snprintf(tc_name, sizeof(tc_name), "channel-%d", i); + scnprintf(tc_name, sizeof(tc_name), "channel-%d", i); struct fwnode_handle *tc_node __free(fwnode_handle) = fwnode_get_named_child_node(ch_node, tc_name); diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index 80b917944b51..ff23219a582a 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -301,6 +301,7 @@ struct iqs7222_dev_desc { int allow_offset; int event_offset; int comms_offset; + int ext_chan; bool legacy_gesture; struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS]; }; @@ -315,6 +316,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { .allow_offset = 9, .event_offset = 10, .comms_offset = 12, + .ext_chan = 10, .reg_grps = { [IQS7222_REG_GRP_STAT] = { .base = IQS7222_SYS_STATUS, @@ -373,6 +375,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { .allow_offset = 9, .event_offset = 10, .comms_offset = 12, + .ext_chan = 10, .legacy_gesture = true, .reg_grps = { [IQS7222_REG_GRP_STAT] = { @@ -2244,7 +2247,7 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; struct i2c_client *client = iqs7222->client; int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; - int ext_chan = rounddown(num_chan, 10); + int ext_chan = dev_desc->ext_chan ? : num_chan; int error, i; u16 *chan_setup = iqs7222->chan_setup[chan_index]; u16 *sys_setup = iqs7222->sys_setup; @@ -2424,6 +2427,9 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, if (error) return error; + if (!iqs7222->kp_type[chan_index][i]) + continue; + if (!dev_desc->event_offset) continue; @@ -2445,7 +2451,7 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; struct i2c_client *client = iqs7222->client; int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; - int ext_chan = rounddown(num_chan, 10); + int ext_chan = dev_desc->ext_chan ? : num_chan; int count, error, reg_offset, i; u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; u16 *sldr_setup = iqs7222->sldr_setup[sldr_index]; diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c index bee4b1376491..70cd6586459e 100644 --- a/drivers/input/misc/keyspan_remote.c +++ b/drivers/input/misc/keyspan_remote.c @@ -420,24 +420,6 @@ static void keyspan_close(struct input_dev *dev) usb_kill_urb(remote->irq_urb); } -static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface) -{ - - struct usb_endpoint_descriptor *endpoint; - int i; - - for (i = 0; i < iface->desc.bNumEndpoints; ++i) { - endpoint = &iface->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) { - /* we found our interrupt in endpoint */ - return endpoint; - } - } - - return NULL; -} - /* * Routine that sets up the driver to handle a specific USB device detected on the bus. */ @@ -449,11 +431,11 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic struct input_dev *input_dev; int i, error; - endpoint = keyspan_get_in_endpoint(interface->cur_altsetting); - if (!endpoint) + error = usb_find_int_in_endpoint(interface->cur_altsetting, &endpoint); + if (error) return -ENODEV; - remote = kzalloc(sizeof(*remote), GFP_KERNEL); + remote = kzalloc_obj(*remote); input_dev = input_allocate_device(); if (!remote || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/misc/max7360-rotary.c b/drivers/input/misc/max7360-rotary.c new file mode 100644 index 000000000000..385831ef34b6 --- /dev/null +++ b/drivers/input/misc/max7360-rotary.c @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2025 Bootlin + * + * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com> + */ + +#include <linux/bitfield.h> +#include <linux/device/devres.h> +#include <linux/dev_printk.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/mfd/max7360.h> +#include <linux/property.h> +#include <linux/platform_device.h> +#include <linux/pm_wakeirq.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#define MAX7360_ROTARY_DEFAULT_STEPS 24 + +struct max7360_rotary { + struct input_dev *input; + struct regmap *regmap; + unsigned int debounce_ms; + + unsigned int pos; + + u32 steps; + u32 axis; + bool relative_axis; + bool rollover; +}; + +static void max7360_rotary_report_event(struct max7360_rotary *max7360_rotary, int steps) +{ + if (max7360_rotary->relative_axis) { + input_report_rel(max7360_rotary->input, max7360_rotary->axis, steps); + } else { + int pos = max7360_rotary->pos; + int maxval = max7360_rotary->steps; + + /* + * Add steps to the position. + * Make sure added steps are always in ]-maxval; maxval[ + * interval, so (pos + maxval) is always >= 0. + * Then set back pos to the [0; maxval[ interval. + */ + pos += steps % maxval; + if (max7360_rotary->rollover) + pos = (pos + maxval) % maxval; + else + pos = clamp(pos, 0, maxval - 1); + + max7360_rotary->pos = pos; + input_report_abs(max7360_rotary->input, max7360_rotary->axis, max7360_rotary->pos); + } + + input_sync(max7360_rotary->input); +} + +static irqreturn_t max7360_rotary_irq(int irq, void *data) +{ + struct max7360_rotary *max7360_rotary = data; + struct device *dev = max7360_rotary->input->dev.parent; + unsigned int val; + int error; + + error = regmap_read(max7360_rotary->regmap, MAX7360_REG_RTR_CNT, &val); + if (error < 0) { + dev_err(dev, "Failed to read rotary counter\n"); + return IRQ_NONE; + } + + if (val == 0) + return IRQ_NONE; + + max7360_rotary_report_event(max7360_rotary, sign_extend32(val, 7)); + + return IRQ_HANDLED; +} + +static int max7360_rotary_hw_init(struct max7360_rotary *max7360_rotary) +{ + struct device *dev = max7360_rotary->input->dev.parent; + int val; + int error; + + val = FIELD_PREP(MAX7360_ROT_DEBOUNCE, max7360_rotary->debounce_ms) | + FIELD_PREP(MAX7360_ROT_INTCNT, 1) | MAX7360_ROT_INTCNT_DLY; + error = regmap_write(max7360_rotary->regmap, MAX7360_REG_RTRCFG, val); + if (error) + dev_err(dev, "Failed to set max7360 rotary encoder configuration\n"); + + return error; +} + +static int max7360_rotary_probe(struct platform_device *pdev) +{ + struct max7360_rotary *max7360_rotary; + struct device *dev = &pdev->dev; + struct input_dev *input; + struct regmap *regmap; + int irq; + int error; + + regmap = dev_get_regmap(dev->parent, NULL); + if (!regmap) + return dev_err_probe(dev, -ENODEV, "Could not get parent regmap\n"); + + irq = fwnode_irq_get_byname(dev_fwnode(dev->parent), "inti"); + if (irq < 0) + return dev_err_probe(dev, irq, "Failed to get IRQ\n"); + + max7360_rotary = devm_kzalloc(dev, sizeof(*max7360_rotary), GFP_KERNEL); + if (!max7360_rotary) + return -ENOMEM; + + max7360_rotary->regmap = regmap; + + device_property_read_u32(dev->parent, "linux,axis", &max7360_rotary->axis); + max7360_rotary->rollover = device_property_read_bool(dev->parent, + "rotary-encoder,rollover"); + max7360_rotary->relative_axis = + device_property_read_bool(dev->parent, "rotary-encoder,relative-axis"); + + error = device_property_read_u32(dev->parent, "rotary-encoder,steps", + &max7360_rotary->steps); + if (error) + max7360_rotary->steps = MAX7360_ROTARY_DEFAULT_STEPS; + + device_property_read_u32(dev->parent, "rotary-debounce-delay-ms", + &max7360_rotary->debounce_ms); + if (max7360_rotary->debounce_ms > MAX7360_ROT_DEBOUNCE_MAX) + return dev_err_probe(dev, -EINVAL, "Invalid debounce timing: %u\n", + max7360_rotary->debounce_ms); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + max7360_rotary->input = input; + + input->id.bustype = BUS_I2C; + input->name = pdev->name; + + if (max7360_rotary->relative_axis) + input_set_capability(input, EV_REL, max7360_rotary->axis); + else + input_set_abs_params(input, max7360_rotary->axis, 0, max7360_rotary->steps, 0, 1); + + error = devm_request_threaded_irq(dev, irq, NULL, max7360_rotary_irq, + IRQF_ONESHOT | IRQF_SHARED, + "max7360-rotary", max7360_rotary); + if (error) + return dev_err_probe(dev, error, "Failed to register interrupt\n"); + + error = input_register_device(input); + if (error) + return dev_err_probe(dev, error, "Could not register input device\n"); + + error = max7360_rotary_hw_init(max7360_rotary); + if (error) + return dev_err_probe(dev, error, "Failed to initialize max7360 rotary\n"); + + device_init_wakeup(dev, true); + error = dev_pm_set_wake_irq(dev, irq); + if (error) + dev_warn(dev, "Failed to set up wakeup irq: %d\n", error); + + return 0; +} + +static void max7360_rotary_remove(struct platform_device *pdev) +{ + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); +} + +static struct platform_driver max7360_rotary_driver = { + .driver = { + .name = "max7360-rotary", + }, + .probe = max7360_rotary_probe, + .remove = max7360_rotary_remove, +}; +module_platform_driver(max7360_rotary_driver); + +MODULE_DESCRIPTION("MAX7360 Rotary driver"); +MODULE_AUTHOR("Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c index cdb9be737e48..5d45680d74a4 100644 --- a/drivers/input/misc/max77693-haptic.c +++ b/drivers/input/misc/max77693-haptic.c @@ -24,6 +24,7 @@ #include <linux/mfd/max77693.h> #include <linux/mfd/max77693-common.h> #include <linux/mfd/max77693-private.h> +#include <linux/mfd/max77705-private.h> #include <linux/mfd/max77843-private.h> #define MAX_MAGNITUDE_SHIFT 16 @@ -67,15 +68,16 @@ struct max77693_haptic { static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic) { - struct pwm_args pargs; - int delta; + struct pwm_state state; int error; - pwm_get_args(haptic->pwm_dev, &pargs); - delta = (pargs.period + haptic->pwm_duty) / 2; - error = pwm_config(haptic->pwm_dev, delta, pargs.period); + pwm_init_state(haptic->pwm_dev, &state); + state.duty_cycle = (state.period + haptic->pwm_duty) / 2; + + error = pwm_apply_might_sleep(haptic->pwm_dev, &state); if (error) { - dev_err(haptic->dev, "failed to configure pwm: %d\n", error); + dev_err(haptic->dev, + "failed to set pwm duty cycle: %d\n", error); return error; } @@ -116,6 +118,13 @@ static int max77693_haptic_configure(struct max77693_haptic *haptic, MAX77693_HAPTIC_PWM_DIVISOR_128); config_reg = MAX77693_HAPTIC_REG_CONFIG2; break; + case TYPE_MAX77705: + value = ((haptic->type << MAX77693_CONFIG2_MODE) | + (enable << MAX77693_CONFIG2_MEN) | + (haptic->mode << MAX77693_CONFIG2_HTYP) | + MAX77693_HAPTIC_PWM_DIVISOR_128); + config_reg = MAX77705_PMIC_REG_MCONFIG; + break; case TYPE_MAX77843: value = (haptic->type << MCONFIG_MODE_SHIFT) | (enable << MCONFIG_MEN_SHIFT) | @@ -158,12 +167,17 @@ static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable) static void max77693_haptic_enable(struct max77693_haptic *haptic) { + struct pwm_state state; int error; if (haptic->enabled) return; - error = pwm_enable(haptic->pwm_dev); + pwm_init_state(haptic->pwm_dev, &state); + state.duty_cycle = (state.period + haptic->pwm_duty) / 2; + state.enabled = true; + + error = pwm_apply_might_sleep(haptic->pwm_dev, &state); if (error) { dev_err(haptic->dev, "failed to enable haptic pwm device: %d\n", error); @@ -216,18 +230,13 @@ static void max77693_haptic_play_work(struct work_struct *work) { struct max77693_haptic *haptic = container_of(work, struct max77693_haptic, work); - int error; - error = max77693_haptic_set_duty_cycle(haptic); - if (error) { - dev_err(haptic->dev, "failed to set duty cycle: %d\n", error); - return; - } - - if (haptic->magnitude) - max77693_haptic_enable(haptic); - else + if (!haptic->magnitude) max77693_haptic_disable(haptic); + else if (haptic->enabled) + max77693_haptic_set_duty_cycle(haptic); + else + max77693_haptic_enable(haptic); } static int max77693_haptic_play_effect(struct input_dev *dev, void *data, @@ -313,6 +322,7 @@ static int max77693_haptic_probe(struct platform_device *pdev) case TYPE_MAX77693: haptic->regmap_haptic = max77693->regmap_haptic; break; + case TYPE_MAX77705: case TYPE_MAX77843: haptic->regmap_haptic = max77693->regmap; break; @@ -331,12 +341,6 @@ static int max77693_haptic_probe(struct platform_device *pdev) return PTR_ERR(haptic->pwm_dev); } - /* - * FIXME: pwm_apply_args() should be removed when switching to the - * atomic PWM API. - */ - pwm_apply_args(haptic->pwm_dev); - haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic"); if (IS_ERR(haptic->motor_reg)) { dev_err(&pdev->dev, "failed to get regulator\n"); @@ -408,6 +412,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops, static const struct platform_device_id max77693_haptic_id[] = { { "max77693-haptic", }, + { "max77705-haptic", }, { "max77843-haptic", }, {}, }; @@ -415,6 +420,7 @@ MODULE_DEVICE_TABLE(platform, max77693_haptic_id); static const struct of_device_id of_max77693_haptic_dt_match[] = { { .compatible = "maxim,max77693-haptic", }, + { .compatible = "maxim,max77705-haptic", }, { .compatible = "maxim,max77843-haptic", }, { /* sentinel */ }, }; @@ -433,5 +439,5 @@ module_platform_driver(max77693_haptic_driver); MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); -MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver"); +MODULE_DESCRIPTION("MAXIM 77693/77705/77843 Haptic driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index f97f341ee0bb..975c3ba023f5 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -53,40 +53,30 @@ struct max8997_haptic { unsigned int pattern_signal_period; }; -static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip) +static void max8997_haptic_set_internal_duty_cycle(struct max8997_haptic *chip) { - int ret = 0; + u8 duty_index = DIV_ROUND_UP(chip->level * 64, 100); - if (chip->mode == MAX8997_EXTERNAL_MODE) { - unsigned int duty = chip->pwm_period * chip->level / 100; - ret = pwm_config(chip->pwm, duty, chip->pwm_period); - } else { - u8 duty_index = 0; - - duty_index = DIV_ROUND_UP(chip->level * 64, 100); - - switch (chip->internal_mode_pattern) { - case 0: - max8997_write_reg(chip->client, - MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index); - break; - case 1: - max8997_write_reg(chip->client, - MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index); - break; - case 2: - max8997_write_reg(chip->client, - MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index); - break; - case 3: - max8997_write_reg(chip->client, - MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index); - break; - default: - break; - } + switch (chip->internal_mode_pattern) { + case 0: + max8997_write_reg(chip->client, + MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index); + break; + case 1: + max8997_write_reg(chip->client, + MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index); + break; + case 2: + max8997_write_reg(chip->client, + MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index); + break; + case 3: + max8997_write_reg(chip->client, + MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index); + break; + default: + break; } - return ret; } static void max8997_haptic_configure(struct max8997_haptic *chip) @@ -155,11 +145,8 @@ static void max8997_haptic_enable(struct max8997_haptic *chip) guard(mutex)(&chip->mutex); - error = max8997_haptic_set_duty_cycle(chip); - if (error) { - dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error); - return; - } + if (chip->mode != MAX8997_EXTERNAL_MODE) + max8997_haptic_set_internal_duty_cycle(chip); if (!chip->enabled) { error = regulator_enable(chip->regulator); @@ -168,16 +155,32 @@ static void max8997_haptic_enable(struct max8997_haptic *chip) return; } max8997_haptic_configure(chip); - if (chip->mode == MAX8997_EXTERNAL_MODE) { - error = pwm_enable(chip->pwm); - if (error) { - dev_err(chip->dev, "Failed to enable PWM\n"); - regulator_disable(chip->regulator); - return; - } + } + + /* + * It would be more straight forward to configure the external PWM + * earlier i.e. when the internal duty_cycle is setup in internal mode. + * But historically this is done only after the regulator was enabled + * and max8997_haptic_configure() set the enable bit in + * MAX8997_HAPTIC_REG_CONF2. So better keep it this way. + */ + if (chip->mode == MAX8997_EXTERNAL_MODE) { + struct pwm_state state; + + pwm_init_state(chip->pwm, &state); + state.period = chip->pwm_period; + state.duty_cycle = chip->pwm_period * chip->level / 100; + state.enabled = true; + + error = pwm_apply_might_sleep(chip->pwm, &state); + if (error) { + dev_err(chip->dev, "Failed to enable PWM\n"); + regulator_disable(chip->regulator); + return; } - chip->enabled = true; } + + chip->enabled = true; } static void max8997_haptic_disable(struct max8997_haptic *chip) @@ -244,7 +247,7 @@ static int max8997_haptic_probe(struct platform_device *pdev) return -EINVAL; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = kzalloc_obj(*chip); input_dev = input_allocate_device(); if (!chip || !input_dev) { dev_err(&pdev->dev, "unable to allocate memory\n"); @@ -282,11 +285,6 @@ static int max8997_haptic_probe(struct platform_device *pdev) goto err_free_mem; } - /* - * FIXME: pwm_apply_args() should be removed when switching to - * the atomic PWM API. - */ - pwm_apply_args(chip->pwm); break; default: diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c index 1c7faa9b7afe..cb781ce967ca 100644 --- a/drivers/input/misc/mc13783-pwrbutton.c +++ b/drivers/input/misc/mc13783-pwrbutton.c @@ -57,7 +57,6 @@ static irqreturn_t button_irq(int irq, void *_priv) struct mc13783_pwrb *priv = _priv; int val; - mc13xxx_irq_ack(priv->mc13783, irq); mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val); switch (irq) { @@ -109,7 +108,7 @@ static int mc13783_pwrbutton_probe(struct platform_device *pdev) return -ENOMEM; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) { err = -ENOMEM; dev_dbg(&pdev->dev, "Can't allocate power button\n"); diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c index 7ba8d166d68c..0c7b8f8ef4a5 100644 --- a/drivers/input/misc/nxp-bbnsm-pwrkey.c +++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c @@ -45,7 +45,7 @@ struct bbnsm_pwrkey { static void bbnsm_pwrkey_check_for_events(struct timer_list *t) { - struct bbnsm_pwrkey *bbnsm = from_timer(bbnsm, t, check_timer); + struct bbnsm_pwrkey *bbnsm = timer_container_of(bbnsm, t, check_timer); struct input_dev *input = bbnsm->input; u32 state; diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 39fc451c56e9..f22083f44d91 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -91,7 +91,7 @@ static irqreturn_t pwron_irq(int irq, void *palmas_pwron) pm_wakeup_event(input_dev->dev.parent, 0); input_sync(input_dev); - mod_delayed_work(system_wq, &pwron->input_work, + mod_delayed_work(system_dfl_wq, &pwron->input_work, msecs_to_jiffies(PALMAS_PWR_KEY_Q_TIME_MS)); return IRQ_HANDLED; @@ -164,7 +164,7 @@ static int palmas_pwron_probe(struct platform_device *pdev) palmas_pwron_params_ofinit(dev, &config); - pwron = kzalloc(sizeof(*pwron), GFP_KERNEL); + pwron = kzalloc_obj(*pwron); if (!pwron) return -ENOMEM; diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c index fe43fd72ba7b..b19899b50d0b 100644 --- a/drivers/input/misc/pcap_keys.c +++ b/drivers/input/misc/pcap_keys.c @@ -49,7 +49,7 @@ static int pcap_keys_probe(struct platform_device *pdev) struct pcap_keys *pcap_keys; struct input_dev *input_dev; - pcap_keys = kmalloc(sizeof(*pcap_keys), GFP_KERNEL); + pcap_keys = kmalloc_obj(*pcap_keys); if (!pcap_keys) return err; diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c deleted file mode 100644 index 6d046e236ba6..000000000000 --- a/drivers/input/misc/pcf50633-input.c +++ /dev/null @@ -1,113 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* NXP PCF50633 Input Driver - * - * (C) 2006-2008 by Openmoko, Inc. - * Author: Balaji Rao <balajirrao@openmoko.org> - * All rights reserved. - * - * Broken down from monstrous PCF50633 driver mainly by - * Harald Welte, Andy Green and Werner Almesberger - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/input.h> -#include <linux/slab.h> - -#include <linux/mfd/pcf50633/core.h> - -#define PCF50633_OOCSTAT_ONKEY 0x01 -#define PCF50633_REG_OOCSTAT 0x12 -#define PCF50633_REG_OOCMODE 0x10 - -struct pcf50633_input { - struct pcf50633 *pcf; - struct input_dev *input_dev; -}; - -static void -pcf50633_input_irq(int irq, void *data) -{ - struct pcf50633_input *input; - int onkey_released; - - input = data; - - /* We report only one event depending on the key press status */ - onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT) - & PCF50633_OOCSTAT_ONKEY; - - if (irq == PCF50633_IRQ_ONKEYF && !onkey_released) - input_report_key(input->input_dev, KEY_POWER, 1); - else if (irq == PCF50633_IRQ_ONKEYR && onkey_released) - input_report_key(input->input_dev, KEY_POWER, 0); - - input_sync(input->input_dev); -} - -static int pcf50633_input_probe(struct platform_device *pdev) -{ - struct pcf50633_input *input; - struct input_dev *input_dev; - int ret; - - - input = kzalloc(sizeof(*input), GFP_KERNEL); - if (!input) - return -ENOMEM; - - input_dev = input_allocate_device(); - if (!input_dev) { - kfree(input); - return -ENOMEM; - } - - platform_set_drvdata(pdev, input); - input->pcf = dev_to_pcf50633(pdev->dev.parent); - input->input_dev = input_dev; - - input_dev->name = "PCF50633 PMU events"; - input_dev->id.bustype = BUS_I2C; - input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR); - set_bit(KEY_POWER, input_dev->keybit); - - ret = input_register_device(input_dev); - if (ret) { - input_free_device(input_dev); - kfree(input); - return ret; - } - pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR, - pcf50633_input_irq, input); - pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF, - pcf50633_input_irq, input); - - return 0; -} - -static void pcf50633_input_remove(struct platform_device *pdev) -{ - struct pcf50633_input *input = platform_get_drvdata(pdev); - - pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR); - pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF); - - input_unregister_device(input->input_dev); - kfree(input); -} - -static struct platform_driver pcf50633_input_driver = { - .driver = { - .name = "pcf50633-input", - }, - .probe = pcf50633_input_probe, - .remove = pcf50633_input_remove, -}; -module_platform_driver(pcf50633_input_driver); - -MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); -MODULE_DESCRIPTION("PCF50633 input driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcf50633-input"); diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 3632cb206e34..14fc6c6cf699 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -91,7 +91,7 @@ static int pcf8574_kp_probe(struct i2c_client *client) return -ENODEV; } - lp = kzalloc(sizeof(*lp), GFP_KERNEL); + lp = kzalloc_obj(*lp); if (!lp) return -ENOMEM; diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c new file mode 100644 index 000000000000..0d1b570bbe47 --- /dev/null +++ b/drivers/input/misc/pf1550-onkey.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the PF1550 ONKEY + * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Portions Copyright (c) 2025 Savoir-faire Linux Inc. + * Samuel Kayode <samuel.kayode@savoirfairelinux.com> + */ + +#include <linux/err.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/pf1550.h> +#include <linux/platform_device.h> + +#define PF1550_ONKEY_IRQ_NR 6 + +struct onkey_drv_data { + struct device *dev; + const struct pf1550_ddata *pf1550; + bool wakeup; + struct input_dev *input; +}; + +static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data) +{ + struct onkey_drv_data *onkey = data; + struct platform_device *pdev = to_platform_device(onkey->dev); + int i, state, irq_type = -1; + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) + if (irq == platform_get_irq(pdev, i)) + irq_type = i; + + switch (irq_type) { + case PF1550_ONKEY_IRQ_PUSHI: + state = 0; + break; + case PF1550_ONKEY_IRQ_1SI: + case PF1550_ONKEY_IRQ_2SI: + case PF1550_ONKEY_IRQ_3SI: + case PF1550_ONKEY_IRQ_4SI: + case PF1550_ONKEY_IRQ_8SI: + state = 1; + break; + default: + dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n", + irq_type); + return IRQ_HANDLED; + } + + input_event(onkey->input, EV_KEY, KEY_POWER, state); + input_sync(onkey->input); + + return IRQ_HANDLED; +} + +static int pf1550_onkey_probe(struct platform_device *pdev) +{ + struct onkey_drv_data *onkey; + struct input_dev *input; + bool key_power = false; + int i, irq, error; + + onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->dev = &pdev->dev; + + onkey->pf1550 = dev_get_drvdata(pdev->dev.parent); + if (!onkey->pf1550->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, + "failed to get regmap\n"); + + onkey->wakeup = device_property_read_bool(pdev->dev.parent, + "wakeup-source"); + + if (device_property_read_bool(pdev->dev.parent, + "nxp,disable-key-power")) { + error = regmap_clear_bits(onkey->pf1550->regmap, + PF1550_PMIC_REG_PWRCTRL1, + PF1550_ONKEY_RST_EN); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed: disable turn system off"); + } else { + key_power = true; + } + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return dev_err_probe(&pdev->dev, -ENOMEM, + "failed to allocate the input device\n"); + + input->name = pdev->name; + input->phys = "pf1550-onkey/input0"; + input->id.bustype = BUS_HOST; + + if (key_power) + input_set_capability(input, EV_KEY, KEY_POWER); + + onkey->input = input; + platform_set_drvdata(pdev, onkey); + + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + return irq; + + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, + pf1550_onkey_irq_handler, + IRQF_NO_SUSPEND, + "pf1550-onkey", onkey); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed: irq request (IRQ: %d)\n", + i); + } + + error = input_register_device(input); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed to register input device\n"); + + device_init_wakeup(&pdev->dev, onkey->wakeup); + + return 0; +} + +static int pf1550_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + int i, irq; + + if (!device_may_wakeup(&pdev->dev)) + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI | + ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI); + else + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + enable_irq_wake(irq); + } + + return 0; +} + +static int pf1550_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct onkey_drv_data *onkey = platform_get_drvdata(pdev); + int i, irq; + + if (!device_may_wakeup(&pdev->dev)) + regmap_write(onkey->pf1550->regmap, + PF1550_PMIC_REG_ONKEY_INT_MASK0, + ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | + ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | + ONKEY_IRQ_8SI))); + else + for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) { + irq = platform_get_irq(pdev, i); + if (irq > 0) + disable_irq_wake(irq); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend, + pf1550_onkey_resume); + +static const struct platform_device_id pf1550_onkey_id[] = { + { "pf1550-onkey", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, pf1550_onkey_id); + +static struct platform_driver pf1550_onkey_driver = { + .driver = { + .name = "pf1550-onkey", + .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops), + }, + .probe = pf1550_onkey_probe, + .id_table = pf1550_onkey_id, +}; +module_platform_driver(pf1550_onkey_driver); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_DESCRIPTION("PF1550 onkey Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index d0c46665e527..53249d2c081f 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -60,6 +60,7 @@ struct pm8941_data { bool supports_ps_hold_poff_config; bool supports_debounce_config; bool has_pon_pbs; + bool wakeup_source_default; const char *name; const char *phys; }; @@ -154,8 +155,8 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data) if (pwrkey->sw_debounce_time_us) { if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) { dev_dbg(pwrkey->dev, - "ignoring key event received before debounce end %llu us\n", - pwrkey->sw_debounce_end_time); + "ignoring key event received before debounce end %lld us\n", + ktime_to_us(pwrkey->sw_debounce_end_time)); return IRQ_HANDLED; } } @@ -245,7 +246,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops, static int pm8941_pwrkey_probe(struct platform_device *pdev) { struct pm8941_pwrkey *pwrkey; - bool pull_up; + bool pull_up, wakeup; struct device *parent; struct device_node *regmap_node; const __be32 *addr; @@ -402,8 +403,11 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) } } + wakeup = pwrkey->data->wakeup_source_default || + of_property_read_bool(pdev->dev.of_node, "wakeup-source"); + platform_set_drvdata(pdev, pwrkey); - device_init_wakeup(&pdev->dev, 1); + device_init_wakeup(&pdev->dev, wakeup); return 0; } @@ -424,6 +428,7 @@ static const struct pm8941_data pwrkey_data = { .supports_ps_hold_poff_config = true, .supports_debounce_config = true, .has_pon_pbs = false, + .wakeup_source_default = true, }; static const struct pm8941_data resin_data = { @@ -434,6 +439,7 @@ static const struct pm8941_data resin_data = { .supports_ps_hold_poff_config = true, .supports_debounce_config = true, .has_pon_pbs = false, + .wakeup_source_default = false, }; static const struct pm8941_data pon_gen3_pwrkey_data = { @@ -443,6 +449,7 @@ static const struct pm8941_data pon_gen3_pwrkey_data = { .supports_ps_hold_poff_config = false, .supports_debounce_config = false, .has_pon_pbs = true, + .wakeup_source_default = true, }; static const struct pm8941_data pon_gen3_resin_data = { @@ -452,6 +459,7 @@ static const struct pm8941_data pon_gen3_resin_data = { .supports_ps_hold_poff_config = false, .supports_debounce_config = false, .has_pon_pbs = true, + .wakeup_source_default = false, }; static const struct of_device_id pm8941_pwr_key_id_table[] = { diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c index ecb92ee5ebbc..754379d2625c 100644 --- a/drivers/input/misc/powermate.c +++ b/drivers/input/misc/powermate.c @@ -275,7 +275,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev if (!pm->data) return -1; - pm->configcr = kmalloc(sizeof(*(pm->configcr)), GFP_KERNEL); + pm->configcr = kmalloc_obj(*(pm->configcr)); if (!pm->configcr) return -ENOMEM; @@ -313,7 +313,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i 0, interface->desc.bInterfaceNumber, NULL, 0, USB_CTRL_SET_TIMEOUT); - pm = kzalloc(sizeof(*pm), GFP_KERNEL); + pm = kzalloc_obj(*pm); input_dev = input_allocate_device(); if (!pm || !input_dev) goto fail1; diff --git a/drivers/input/misc/qnap-mcu-input.c b/drivers/input/misc/qnap-mcu-input.c index 76e62f0816c1..3be899bfc114 100644 --- a/drivers/input/misc/qnap-mcu-input.c +++ b/drivers/input/misc/qnap-mcu-input.c @@ -103,7 +103,7 @@ static int qnap_mcu_input_probe(struct platform_device *pdev) input = devm_input_allocate_device(dev); if (!input) - return dev_err_probe(dev, -ENOMEM, "no memory for input device\n"); + return -ENOMEM; idev->input = input; idev->dev = dev; diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index 190a80e1e2c1..40173bf7a235 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -8,7 +8,7 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <asm/mach-rc32434/gpio.h> #include <asm/mach-rc32434/rb.h> @@ -18,6 +18,14 @@ #define RB532_BTN_RATE 100 /* msec */ #define RB532_BTN_KSYM BTN_0 +/** + * struct rb532_button - RB532 button information + * @gpio: GPIO connected to the button + */ +struct rb532_button { + struct gpio_desc *gpio; +}; + /* The S1 button state is provided by GPIO pin 1. But as this * pin is also used for uart input as alternate function, the * operational modes must be switched first: @@ -31,35 +39,48 @@ * The GPIO value occurs to be inverted, so pin high means * button is not pressed. */ -static bool rb532_button_pressed(void) +static bool rb532_button_pressed(struct rb532_button *button) { int val; set_latch_u5(0, LO_FOFF); - gpio_direction_input(GPIO_BTN_S1); + gpiod_direction_input(button->gpio); - val = gpio_get_value(GPIO_BTN_S1); + val = gpiod_get_value(button->gpio); rb532_gpio_set_func(GPIO_BTN_S1); set_latch_u5(LO_FOFF, 0); - return !val; + return val; } static void rb532_button_poll(struct input_dev *input) { - input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed()); + struct rb532_button *button = input_get_drvdata(input); + + input_report_key(input, RB532_BTN_KSYM, rb532_button_pressed(button)); input_sync(input); } static int rb532_button_probe(struct platform_device *pdev) { + struct rb532_button *button; struct input_dev *input; int error; + button = devm_kzalloc(&pdev->dev, sizeof(*button), GFP_KERNEL); + if (!button) + return -ENOMEM; + + button->gpio = devm_gpiod_get(&pdev->dev, "button", GPIOD_IN); + if (IS_ERR(button->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(button->gpio), + "error getting button GPIO\n"); + input = devm_input_allocate_device(&pdev->dev); if (!input) return -ENOMEM; + input_set_drvdata(input, button); input->name = "rb532 button"; input->phys = "rb532/button0"; @@ -77,6 +98,8 @@ static int rb532_button_probe(struct platform_device *pdev) if (error) return error; + platform_set_drvdata(pdev, button); + return 0; } diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 8d7303fc13bc..1cfadd73829f 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -74,9 +74,14 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int return -1; switch (code) { - case SND_BELL: if (value) value = 1000; - case SND_TONE: break; - default: return -1; + case SND_BELL: + if (value) + value = 1000; + break; + case SND_TONE: + break; + default: + return -1; } if (value > 20 && value < 32767) @@ -109,9 +114,14 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned return -1; switch (code) { - case SND_BELL: if (value) value = 1000; - case SND_TONE: break; - default: return -1; + case SND_BELL: + if (value) + value = 1000; + break; + case SND_TONE: + break; + default: + return -1; } if (value > 20 && value < 32767) diff --git a/drivers/input/misc/tps6594-pwrbutton.c b/drivers/input/misc/tps6594-pwrbutton.c new file mode 100644 index 000000000000..cd039b3866dc --- /dev/null +++ b/drivers/input/misc/tps6594-pwrbutton.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * power button driver for TI TPS6594 PMICs + * + * Copyright (C) 2025 Critical Link LLC - https://www.criticallink.com/ + */ +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/tps6594.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +struct tps6594_pwrbutton { + struct device *dev; + struct input_dev *idev; + char phys[32]; +}; + +static irqreturn_t tps6594_pb_push_irq(int irq, void *_pwr) +{ + struct tps6594_pwrbutton *pwr = _pwr; + + input_report_key(pwr->idev, KEY_POWER, 1); + pm_wakeup_event(pwr->dev, 0); + input_sync(pwr->idev); + + return IRQ_HANDLED; +} + +static irqreturn_t tps6594_pb_release_irq(int irq, void *_pwr) +{ + struct tps6594_pwrbutton *pwr = _pwr; + + input_report_key(pwr->idev, KEY_POWER, 0); + input_sync(pwr->idev); + + return IRQ_HANDLED; +} + +static int tps6594_pb_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tps6594_pwrbutton *pwr; + struct input_dev *idev; + int error; + int push_irq; + int release_irq; + + pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL); + if (!pwr) + return -ENOMEM; + + idev = devm_input_allocate_device(dev); + if (!idev) + return -ENOMEM; + + idev->name = pdev->name; + snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0", + pdev->name); + idev->phys = pwr->phys; + idev->id.bustype = BUS_I2C; + + input_set_capability(idev, EV_KEY, KEY_POWER); + + pwr->dev = dev; + pwr->idev = idev; + device_init_wakeup(dev, true); + + push_irq = platform_get_irq(pdev, 0); + if (push_irq < 0) + return -EINVAL; + + release_irq = platform_get_irq(pdev, 1); + if (release_irq < 0) + return -EINVAL; + + error = devm_request_threaded_irq(dev, push_irq, NULL, + tps6594_pb_push_irq, + IRQF_ONESHOT, + pdev->resource[0].name, pwr); + if (error) { + dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq, + error); + return error; + } + + error = devm_request_threaded_irq(dev, release_irq, NULL, + tps6594_pb_release_irq, + IRQF_ONESHOT, + pdev->resource[1].name, pwr); + if (error) { + dev_err(dev, "failed to request release IRQ #%d: %d\n", + release_irq, error); + return error; + } + + error = input_register_device(idev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + return 0; +} + +static const struct platform_device_id tps6594_pwrbtn_id_table[] = { + { "tps6594-pwrbutton", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, tps6594_pwrbtn_id_table); + +static struct platform_driver tps6594_pb_driver = { + .probe = tps6594_pb_probe, + .driver = { + .name = "tps6594_pwrbutton", + }, + .id_table = tps6594_pwrbtn_id_table, +}; +module_platform_driver(tps6594_pb_driver); + +MODULE_DESCRIPTION("TPS6594 Power Button"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index f85cc289c053..b0feef19515d 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -20,27 +20,43 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <linux/bits.h> #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/input.h> #include <linux/interrupt.h> -#include <linux/of.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/platform_device.h> #include <linux/mfd/twl.h> -#define PWR_PWRON_IRQ (1 << 0) +#define PWR_PWRON_IRQ BIT(0) -#define STS_HW_CONDITIONS 0xf +struct twl_pwrbutton_chipdata { + u8 status_reg; + bool need_manual_irq; +}; + +static const struct twl_pwrbutton_chipdata twl4030_chipdata = { + .status_reg = 0xf, + .need_manual_irq = false, +}; + +static const struct twl_pwrbutton_chipdata twl6030_chipdata = { + .status_reg = 0x2, + .need_manual_irq = true, +}; static irqreturn_t powerbutton_irq(int irq, void *_pwr) { struct input_dev *pwr = _pwr; + const struct twl_pwrbutton_chipdata *pdata = dev_get_drvdata(pwr->dev.parent); int err; u8 value; - err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, STS_HW_CONDITIONS); + err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &value, pdata->status_reg); if (!err) { pm_wakeup_event(pwr->dev.parent, 0); input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); @@ -55,10 +71,17 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr) static int twl4030_pwrbutton_probe(struct platform_device *pdev) { + const struct twl_pwrbutton_chipdata *pdata; struct input_dev *pwr; int irq = platform_get_irq(pdev, 0); int err; + pdata = device_get_match_data(&pdev->dev); + if (!pdata) + return -EINVAL; + + platform_set_drvdata(pdev, (void *)pdata); + pwr = devm_input_allocate_device(&pdev->dev); if (!pwr) { dev_err(&pdev->dev, "Can't allocate power button\n"); @@ -85,24 +108,50 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev) return err; } + if (pdata->need_manual_irq) { + err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_LINE_A); + if (err) + return err; + + err = twl6030_interrupt_unmask(0x01, REG_INT_MSK_STS_A); + if (err) + return err; + } + device_init_wakeup(&pdev->dev, true); return 0; } -#ifdef CONFIG_OF +static void twl4030_pwrbutton_remove(struct platform_device *pdev) +{ + const struct twl_pwrbutton_chipdata *pdata = platform_get_drvdata(pdev); + + if (pdata->need_manual_irq) { + twl6030_interrupt_mask(0x01, REG_INT_MSK_LINE_A); + twl6030_interrupt_mask(0x01, REG_INT_MSK_STS_A); + } +} + static const struct of_device_id twl4030_pwrbutton_dt_match_table[] = { - { .compatible = "ti,twl4030-pwrbutton" }, - {}, + { + .compatible = "ti,twl4030-pwrbutton", + .data = &twl4030_chipdata, + }, + { + .compatible = "ti,twl6030-pwrbutton", + .data = &twl6030_chipdata, + }, + { } }; MODULE_DEVICE_TABLE(of, twl4030_pwrbutton_dt_match_table); -#endif static struct platform_driver twl4030_pwrbutton_driver = { .probe = twl4030_pwrbutton_probe, + .remove = twl4030_pwrbutton_remove, .driver = { .name = "twl4030_pwrbutton", - .of_match_table = of_match_ptr(twl4030_pwrbutton_dt_match_table), + .of_match_table = twl4030_pwrbutton_dt_match_table, }, }; module_platform_driver(twl4030_pwrbutton_driver); diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2c51ea9d01d7..d32fa4b508fc 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -25,8 +25,10 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> +#include <linux/lockdep.h> #include <linux/miscdevice.h> #include <linux/overflow.h> +#include <linux/spinlock.h> #include <linux/input/mt.h> #include "../input-compat.h" @@ -57,6 +59,7 @@ struct uinput_device { struct input_dev *dev; struct mutex mutex; enum uinput_state state; + spinlock_t state_lock; wait_queue_head_t waitq; unsigned char ready; unsigned char head; @@ -75,6 +78,8 @@ static int uinput_dev_event(struct input_dev *dev, struct uinput_device *udev = input_get_drvdata(dev); struct timespec64 ts; + lockdep_assert_held(&dev->event_lock); + ktime_get_ts64(&ts); udev->buff[udev->head] = (struct input_event) { @@ -146,27 +151,26 @@ static void uinput_request_release_slot(struct uinput_device *udev, static int uinput_request_send(struct uinput_device *udev, struct uinput_request *request) { - int retval; + unsigned long flags; + int retval = 0; - retval = mutex_lock_interruptible(&udev->mutex); - if (retval) - return retval; + spin_lock(&udev->state_lock); if (udev->state != UIST_CREATED) { retval = -ENODEV; goto out; } - init_completion(&request->done); - /* * Tell our userspace application about this new request * by queueing an input event. */ + spin_lock_irqsave(&udev->dev->event_lock, flags); uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); + spin_unlock_irqrestore(&udev->dev->event_lock, flags); out: - mutex_unlock(&udev->mutex); + spin_unlock(&udev->state_lock); return retval; } @@ -175,6 +179,13 @@ static int uinput_request_submit(struct uinput_device *udev, { int retval; + /* + * Initialize completion before allocating the request slot. + * Once the slot is allocated, uinput_flush_requests() may + * complete it at any time, so it must be initialized first. + */ + init_completion(&request->done); + retval = uinput_request_reserve_slot(udev, request); if (retval) return retval; @@ -289,7 +300,14 @@ static void uinput_destroy_device(struct uinput_device *udev) struct input_dev *dev = udev->dev; enum uinput_state old_state = udev->state; + /* + * Update state under state_lock so that concurrent + * uinput_request_send() sees the state change before we + * flush pending requests and tear down the device. + */ + spin_lock(&udev->state_lock); udev->state = UIST_NEW_DEVICE; + spin_unlock(&udev->state_lock); if (dev) { name = dev->name; @@ -366,7 +384,9 @@ static int uinput_create_device(struct uinput_device *udev) if (error) goto fail2; + spin_lock(&udev->state_lock); udev->state = UIST_CREATED; + spin_unlock(&udev->state_lock); return 0; @@ -379,11 +399,12 @@ static int uinput_open(struct inode *inode, struct file *file) { struct uinput_device *newdev; - newdev = kzalloc(sizeof(*newdev), GFP_KERNEL); + newdev = kzalloc_obj(*newdev); if (!newdev) return -ENOMEM; mutex_init(&newdev->mutex); + spin_lock_init(&newdev->state_lock); spin_lock_init(&newdev->requests_lock); init_waitqueue_head(&newdev->requests_waitq); init_waitqueue_head(&newdev->waitq); @@ -775,6 +796,7 @@ static int uinput_ff_upload_to_user(char __user *buffer, if (in_compat_syscall()) { struct uinput_ff_upload_compat ff_up_compat; + memset(&ff_up_compat, 0, sizeof(ff_up_compat)); ff_up_compat.request_id = ff_up->request_id; ff_up_compat.retval = ff_up->retval; /* diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 67f1c7364c95..6471d836f6fe 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -205,7 +205,7 @@ static int xenkbd_probe(struct xenbus_device *dev, struct xenkbd_info *info; struct input_dev *kbd, *ptr, *mtouch; - info = kzalloc(sizeof(*info), GFP_KERNEL); + info = kzalloc_obj(*info); if (!info) { xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 08dc53ae1b3c..8786ed8b3565 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -831,7 +831,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; - yld = kzalloc(sizeof(*yld), GFP_KERNEL); + yld = kzalloc_obj(*yld); if (!yld) return -ENOMEM; @@ -854,7 +854,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!yld->ctl_data) return usb_cleanup(yld, -ENOMEM); - yld->ctl_req = kmalloc(sizeof(*(yld->ctl_req)), GFP_KERNEL); + yld->ctl_req = kmalloc_obj(*(yld->ctl_req)); if (yld->ctl_req == NULL) return usb_cleanup(yld, -ENOMEM); diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 833b643f0616..074130d88953 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -164,16 +164,6 @@ config MOUSE_PS2_TOUCHKIT If unsure, say N. -config MOUSE_PS2_OLPC - bool "OLPC PS/2 mouse protocol extension" - depends on MOUSE_PS2 && OLPC - help - Say Y here if you have an OLPC XO-1 laptop (with built-in - PS/2 touchpad/tablet device). The manufacturer calls the - touchpad an HGPK. - - If unsure, say N. - config MOUSE_PS2_FOCALTECH bool "FocalTech PS/2 mouse protocol extension" if EXPERT default y @@ -300,42 +290,6 @@ config MOUSE_ELAN_I2C_SMBUS If unsure, say Y. -config MOUSE_INPORT - tristate "InPort/MS/ATIXL busmouse" - depends on ISA - help - Say Y here if you have an InPort, Microsoft or ATI XL busmouse. - They are rather rare these days. - - To compile this driver as a module, choose M here: the - module will be called inport. - -config MOUSE_ATIXL - bool "ATI XL variant" - depends on MOUSE_INPORT - help - Say Y here if your mouse is of the ATI XL variety. - -config MOUSE_LOGIBM - tristate "Logitech busmouse" - depends on ISA - help - Say Y here if you have a Logitech busmouse. - They are rather rare these days. - - To compile this driver as a module, choose M here: the - module will be called logibm. - -config MOUSE_PC110PAD - tristate "IBM PC110 touchpad" - depends on ISA - help - Say Y if you have the IBM PC-110 micro-notebook and want its - touchpad supported. - - To compile this driver as a module, choose M here: the - module will be called pc110pad. - config MOUSE_AMIGA tristate "Amiga mouse" depends on AMIGA diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index a1336d5bee6f..ed40f141691e 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -12,10 +12,7 @@ obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o -obj-$(CONFIG_MOUSE_INPORT) += inport.o -obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o -obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o @@ -29,7 +26,6 @@ psmouse-objs := psmouse-base.o synaptics.o focaltech.o psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o -psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0728b5c08f02..0ee1a30b9aaf 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -12,6 +12,7 @@ * tpconfig utility (by C. Scott Ananian and Bruce Kall). */ +#include "linux/workqueue.h" #include <linux/slab.h> #include <linux/input.h> #include <linux/input/mt.h> @@ -1408,9 +1409,9 @@ static int alps_do_register_bare_ps2_mouse(struct alps_data *priv) return -ENOMEM; } - snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s", - psmouse->ps2dev.serio->phys, - (priv->dev2 ? "input2" : "input1")); + scnprintf(priv->phys3, sizeof(priv->phys3), "%s/%s", + psmouse->ps2dev.serio->phys, + (priv->dev2 ? "input2" : "input1")); dev3->phys = priv->phys3; /* @@ -1452,7 +1453,7 @@ err_free_input: static void alps_register_bare_ps2_mouse(struct work_struct *work) { struct alps_data *priv = container_of(work, struct alps_data, - dev3_register_work.work); + dev3_register_work); int error; guard(mutex)(&alps_mutex); @@ -1485,8 +1486,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse, } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) { /* Register dev3 mouse if we received PS/2 packet first time */ if (!IS_ERR(priv->dev3)) - psmouse_queue_work(psmouse, &priv->dev3_register_work, - 0); + schedule_work(&priv->dev3_register_work); return; } else { dev = priv->dev3; @@ -1519,7 +1519,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) return PSMOUSE_GOOD_DATA; } - del_timer(&priv->timer); + timer_delete(&priv->timer); if (psmouse->packet[6] & 0x80) { @@ -1582,7 +1582,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) static void alps_flush_packet(struct timer_list *t) { - struct alps_data *priv = from_timer(priv, t, timer); + struct alps_data *priv = timer_container_of(priv, t, timer); struct psmouse *psmouse = priv->psmouse; guard(serio_pause_rx)(psmouse->ps2dev.serio); @@ -2975,6 +2975,7 @@ static void alps_disconnect(struct psmouse *psmouse) psmouse_reset(psmouse); timer_shutdown_sync(&priv->timer); + disable_work_sync(&priv->dev3_register_work); if (priv->dev2) input_unregister_device(priv->dev2); if (!IS_ERR_OR_NULL(priv->dev3)) @@ -3103,8 +3104,8 @@ int alps_init(struct psmouse *psmouse) goto init_fail; } - snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1", - psmouse->ps2dev.serio->phys); + scnprintf(priv->phys2, sizeof(priv->phys2), "%s/input1", + psmouse->ps2dev.serio->phys); dev2->phys = priv->phys2; /* @@ -3146,8 +3147,7 @@ int alps_init(struct psmouse *psmouse) priv->psmouse = psmouse; - INIT_DELAYED_WORK(&priv->dev3_register_work, - alps_register_bare_ps2_mouse); + INIT_WORK(&priv->dev3_register_work, alps_register_bare_ps2_mouse); psmouse->protocol_handler = alps_process_byte; psmouse->poll = alps_poll; @@ -3205,7 +3205,7 @@ int alps_detect(struct psmouse *psmouse, bool set_properties) */ psmouse_reset(psmouse); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 0a1048cf23f6..17bbf6cdba55 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -257,7 +257,7 @@ struct alps_fields { * @dev3: Generic PS/2 mouse (can be NULL, delayed registering). * @phys2: Physical path for the trackstick device. * @phys3: Physical path for the generic PS/2 mouse. - * @dev3_register_work: Delayed work for registering PS/2 mouse. + * @dev3_register_work: A work instance for registering PS/2 mouse. * @nibble_commands: Command mapping used for touchpad register accesses. * @addr_command: Command used to tell the touchpad that a register address * follows. @@ -289,7 +289,7 @@ struct alps_data { struct input_dev *dev3; char phys2[32]; char phys3[32]; - struct delayed_work dev3_register_work; + struct work_struct dev3_register_work; /* these are autodetected when the device is identified */ const struct alps_nibble_commands *nibble_commands; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index e669f86f1882..eebeb57515e1 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -200,7 +200,6 @@ struct atp { u8 *data; /* transferred data */ struct input_dev *input; /* input dev */ const struct atp_info *info; /* touchpad model */ - bool open; bool valid; /* are the samples valid? */ bool size_detect_done; bool overflow_warned; @@ -800,7 +799,6 @@ static int atp_open(struct input_dev *input) if (usb_submit_urb(dev->urb, GFP_KERNEL)) return -EIO; - dev->open = true; return 0; } @@ -810,7 +808,6 @@ static void atp_close(struct input_dev *input) usb_kill_urb(dev->urb); cancel_work_sync(&dev->work); - dev->open = false; } static int atp_handle_geyser(struct atp *dev) @@ -832,30 +829,21 @@ static int atp_probe(struct usb_interface *iface, struct atp *dev; struct input_dev *input_dev; struct usb_device *udev = interface_to_usbdev(iface); - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; - int int_in_endpointAddr = 0; - int i, error = -ENOMEM; + struct usb_endpoint_descriptor *ep; + int error; const struct atp_info *info = (const struct atp_info *)id->driver_info; /* set up the endpoint information */ /* use only the first interrupt-in endpoint */ - iface_desc = iface->cur_altsetting; - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - endpoint = &iface_desc->endpoint[i].desc; - if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { - /* we found an interrupt in endpoint */ - int_in_endpointAddr = endpoint->bEndpointAddress; - break; - } - } - if (!int_in_endpointAddr) { + error = usb_find_int_in_endpoint(iface->cur_altsetting, &ep); + if (error) { dev_err(&iface->dev, "Could not find int-in endpoint\n"); return -EIO; } /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + error = -ENOMEM; + dev = kzalloc_obj(*dev); input_dev = input_allocate_device(); if (!dev || !input_dev) { dev_err(&iface->dev, "Out of memory\n"); @@ -878,7 +866,7 @@ static int atp_probe(struct usb_interface *iface, goto err_free_urb; usb_fill_int_urb(dev->urb, udev, - usb_rcvintpipe(udev, int_in_endpointAddr), + usb_rcvintpipe(udev, usb_endpoint_num(ep)), dev->data, dev->info->datalen, dev->info->callback, dev, 1); @@ -963,7 +951,8 @@ static int atp_recover(struct atp *dev) if (error) return error; - if (dev->open && usb_submit_urb(dev->urb, GFP_KERNEL)) + guard(mutex)(&dev->input->mutex); + if (input_device_enabled(dev->input) && usb_submit_urb(dev->urb, GFP_KERNEL)) return -EIO; return 0; @@ -981,7 +970,8 @@ static int atp_resume(struct usb_interface *iface) { struct atp *dev = usb_get_intfdata(iface); - if (dev->open && usb_submit_urb(dev->urb, GFP_KERNEL)) + guard(mutex)(&dev->input->mutex); + if (input_device_enabled(dev->input) && usb_submit_urb(dev->urb, GFP_KERNEL)) return -EIO; return 0; diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index dfdfb59cc8b5..e772bac3b64c 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -286,6 +286,8 @@ struct bcm5974 { const struct tp_finger *index[MAX_FINGERS]; /* finger index data */ struct input_mt_pos pos[MAX_FINGERS]; /* position array */ int slots[MAX_FINGERS]; /* slot assignments */ + struct work_struct mode_reset_work; + unsigned long last_mode_reset; }; /* trackpad finger block data, le16-aligned */ @@ -696,6 +698,32 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on) return retval; } +/* + * Mode switches sent before the control response are ignored. + * Fixing this state requires switching to normal mode and waiting + * about 1ms before switching back to wellspring mode. + */ +static void bcm5974_mode_reset_work(struct work_struct *work) +{ + struct bcm5974 *dev = container_of(work, struct bcm5974, mode_reset_work); + int error; + + guard(mutex)(&dev->pm_mutex); + dev->last_mode_reset = jiffies; + + error = bcm5974_wellspring_mode(dev, false); + if (error) { + dev_err(&dev->intf->dev, "reset to normal mode failed\n"); + return; + } + + fsleep(1000); + + error = bcm5974_wellspring_mode(dev, true); + if (error) + dev_err(&dev->intf->dev, "mode switch after reset failed\n"); +} + static void bcm5974_irq_button(struct urb *urb) { struct bcm5974 *dev = urb->context; @@ -752,10 +780,20 @@ static void bcm5974_irq_trackpad(struct urb *urb) if (dev->tp_urb->actual_length == 2) goto exit; - if (report_tp_state(dev, dev->tp_urb->actual_length)) + if (report_tp_state(dev, dev->tp_urb->actual_length)) { dprintk(1, "bcm5974: bad trackpad package, length: %d\n", dev->tp_urb->actual_length); + /* + * Receiving a HID packet means we aren't in wellspring mode. + * If we haven't tried a reset in the last second, try now. + */ + if (dev->tp_urb->actual_length == 8 && + time_after(jiffies, dev->last_mode_reset + msecs_to_jiffies(1000))) { + schedule_work(&dev->mode_reset_work); + } + } + exit: error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); if (error) @@ -895,7 +933,7 @@ static int bcm5974_probe(struct usb_interface *iface, cfg = bcm5974_get_config(udev); /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = kzalloc_obj(*dev); input_dev = input_allocate_device(); if (!dev || !input_dev) { dev_err(&iface->dev, "out of memory\n"); @@ -906,6 +944,7 @@ static int bcm5974_probe(struct usb_interface *iface, dev->intf = iface; dev->input = input_dev; dev->cfg = *cfg; + INIT_WORK(&dev->mode_reset_work, bcm5974_mode_reset_work); mutex_init(&dev->pm_mutex); /* setup urbs */ @@ -998,6 +1037,7 @@ static void bcm5974_disconnect(struct usb_interface *iface) { struct bcm5974 *dev = usb_get_intfdata(iface); + disable_work_sync(&dev->mode_reset_work); usb_set_intfdata(iface, NULL); input_unregister_device(dev->input); diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 654b38d249f3..f5770a3af2f1 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -251,7 +251,7 @@ static void byd_report_input(struct psmouse *psmouse) static void byd_clear_touch(struct timer_list *t) { - struct byd_data *priv = from_timer(priv, t, timer); + struct byd_data *priv = timer_container_of(priv, t, timer); struct psmouse *psmouse = priv->psmouse; guard(serio_pause_rx)(psmouse->ps2dev.serio); @@ -314,10 +314,8 @@ static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) break; } default: - psmouse_warn(psmouse, - "Unrecognized Z: pkt = %02x %02x %02x %02x\n", - psmouse->packet[0], psmouse->packet[1], - psmouse->packet[2], psmouse->packet[3]); + psmouse_warn(psmouse, "Unrecognized Z: pkt = %*ph\n", + 4, psmouse->packet); return PSMOUSE_BAD_DATA; } @@ -425,7 +423,7 @@ static void byd_disconnect(struct psmouse *psmouse) struct byd_data *priv = psmouse->private; if (priv) { - del_timer(&priv->timer); + timer_delete(&priv->timer); kfree(psmouse->private); psmouse->private = NULL; } @@ -471,7 +469,7 @@ int byd_init(struct psmouse *psmouse) if (byd_reset_touchpad(psmouse)) return -EIO; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 2f2d925a55d7..6e0d956617a1 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -403,7 +403,6 @@ static int cyapa_open(struct input_dev *input) } pm_runtime_get_sync(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); out: mutex_unlock(&cyapa->state_sync_lock); @@ -666,7 +665,6 @@ out: pm_runtime_enable(dev); pm_runtime_get_sync(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); } @@ -710,7 +708,6 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) * process. */ pm_runtime_get_sync(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); } @@ -1080,8 +1077,8 @@ static ssize_t cyapa_update_fw_store(struct device *dev, char fw_name[NAME_MAX]; int ret, error; - if (count >= NAME_MAX) { - dev_err(dev, "File name too long\n"); + if (!count || count >= NAME_MAX) { + dev_err(dev, "Bad file name size\n"); return -EINVAL; } diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 3b4439f10635..59f6e97d5482 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -2833,7 +2833,6 @@ static int cyapa_pip_event_process(struct cyapa *cyapa, * process. */ pm_runtime_get_sync(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); return 0; } else if (report_id != PIP_TOUCH_REPORT_ID && diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c index 9446657a5f35..309063d07b4d 100644 --- a/drivers/input/mouse/cypress_ps2.c +++ b/drivers/input/mouse/cypress_ps2.c @@ -624,7 +624,7 @@ int cypress_init(struct psmouse *psmouse) struct cytp_data *cytp; int error; - cytp = kzalloc(sizeof(*cytp), GFP_KERNEL); + cytp = kzalloc_obj(*cytp); if (!cytp) return -ENOMEM; diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index fee1796da3d0..5cba02a156ce 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -162,6 +162,9 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, case 0x15: *validpage_count = 1024; break; + case 0x19: + *validpage_count = 2032; + break; default: /* unknown ic type clear value */ *validpage_count = 0; @@ -645,6 +648,11 @@ static ssize_t elan_sysfs_update_fw(struct device *dev, return error; } + if (fw->size < data->fw_signature_address + sizeof(signature)) { + dev_err(dev, "firmware file too small\n"); + return -EBADF; + } + /* Firmware file must match signature data */ fw_signature = &fw->data[data->fw_signature_address]; if (memcmp(fw_signature, signature, sizeof(signature)) != 0) { diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index a9057d124a88..88d4070d4b44 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -690,7 +690,7 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client, if (error) { dev_err(dev, "device reset failed: %d\n", error); } else if (!wait_for_completion_timeout(completion, - msecs_to_jiffies(300))) { + msecs_to_jiffies(700))) { dev_err(dev, "timeout waiting for device reset\n"); error = -ETIMEDOUT; } diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 79ad98cc1e79..f8575b80d19d 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -2074,7 +2074,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse, int error = -EINVAL; struct input_dev *tp_dev; - psmouse->private = etd = kzalloc(sizeof(*etd), GFP_KERNEL); + psmouse->private = etd = kzalloc_obj(*etd); if (!etd) return -ENOMEM; diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c index 356b99d48544..43f9939b7c63 100644 --- a/drivers/input/mouse/focaltech.c +++ b/drivers/input/mouse/focaltech.c @@ -408,7 +408,7 @@ int focaltech_init(struct psmouse *psmouse) struct focaltech_data *priv; int error; - psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL); + psmouse->private = priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c deleted file mode 100644 index 6125652e5ad8..000000000000 --- a/drivers/input/mouse/hgpk.c +++ /dev/null @@ -1,1063 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * OLPC HGPK (XO-1) touchpad PS/2 mouse driver - * - * Copyright (c) 2006-2008 One Laptop Per Child - * Authors: - * Zephaniah E. Hull - * Andres Salomon <dilinger@debian.org> - * - * This driver is partly based on the ALPS driver, which is: - * - * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au> - * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com> - * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru> - * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> - */ - -/* - * The spec from ALPS is available from - * <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this - * device as HGPK (Hybrid GS, PT, and Keymatrix). - * - * The earliest versions of the device had simultaneous reporting; that - * was removed. After that, the device used the Advanced Mode GS/PT streaming - * stuff. That turned out to be too buggy to support, so we've finally - * switched to Mouse Mode (which utilizes only the center 1/3 of the touchpad). - */ - -#define DEBUG -#include <linux/slab.h> -#include <linux/input.h> -#include <linux/module.h> -#include <linux/serio.h> -#include <linux/libps2.h> -#include <linux/delay.h> -#include <asm/olpc.h> - -#include "psmouse.h" -#include "hgpk.h" - -#define ILLEGAL_XY 999999 - -static bool tpdebug; -module_param(tpdebug, bool, 0644); -MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); - -static int recalib_delta = 100; -module_param(recalib_delta, int, 0644); -MODULE_PARM_DESC(recalib_delta, - "packets containing a delta this large will be discarded, and a " - "recalibration may be scheduled."); - -static int jumpy_delay = 20; -module_param(jumpy_delay, int, 0644); -MODULE_PARM_DESC(jumpy_delay, - "delay (ms) before recal after jumpiness detected"); - -static int spew_delay = 1; -module_param(spew_delay, int, 0644); -MODULE_PARM_DESC(spew_delay, - "delay (ms) before recal after packet spew detected"); - -static int recal_guard_time; -module_param(recal_guard_time, int, 0644); -MODULE_PARM_DESC(recal_guard_time, - "interval (ms) during which recal will be restarted if packet received"); - -static int post_interrupt_delay = 40; -module_param(post_interrupt_delay, int, 0644); -MODULE_PARM_DESC(post_interrupt_delay, - "delay (ms) before recal after recal interrupt detected"); - -static bool autorecal = true; -module_param(autorecal, bool, 0644); -MODULE_PARM_DESC(autorecal, "enable recalibration in the driver"); - -static char hgpk_mode_name[16]; -module_param_string(hgpk_mode, hgpk_mode_name, sizeof(hgpk_mode_name), 0644); -MODULE_PARM_DESC(hgpk_mode, - "default hgpk mode: mouse, glidesensor or pentablet"); - -static int hgpk_default_mode = HGPK_MODE_MOUSE; - -static const char * const hgpk_mode_names[] = { - [HGPK_MODE_MOUSE] = "Mouse", - [HGPK_MODE_GLIDESENSOR] = "GlideSensor", - [HGPK_MODE_PENTABLET] = "PenTablet", -}; - -static int hgpk_mode_from_name(const char *buf, int len) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(hgpk_mode_names); i++) { - const char *name = hgpk_mode_names[i]; - if (strlen(name) == len && !strncasecmp(name, buf, len)) - return i; - } - - return HGPK_MODE_INVALID; -} - -/* - * see if new value is within 20% of half of old value - */ -static int approx_half(int curr, int prev) -{ - int belowhalf, abovehalf; - - if (curr < 5 || prev < 5) - return 0; - - belowhalf = (prev * 8) / 20; - abovehalf = (prev * 12) / 20; - - return belowhalf < curr && curr <= abovehalf; -} - -/* - * Throw out oddly large delta packets, and any that immediately follow whose - * values are each approximately half of the previous. It seems that the ALPS - * firmware emits errant packets, and they get averaged out slowly. - */ -static int hgpk_discard_decay_hack(struct psmouse *psmouse, int x, int y) -{ - struct hgpk_data *priv = psmouse->private; - int avx, avy; - bool do_recal = false; - - avx = abs(x); - avy = abs(y); - - /* discard if too big, or half that but > 4 times the prev delta */ - if (avx > recalib_delta || - (avx > recalib_delta / 2 && ((avx / 4) > priv->xlast))) { - psmouse_warn(psmouse, "detected %dpx jump in x\n", x); - priv->xbigj = avx; - } else if (approx_half(avx, priv->xbigj)) { - psmouse_warn(psmouse, "detected secondary %dpx jump in x\n", x); - priv->xbigj = avx; - priv->xsaw_secondary++; - } else { - if (priv->xbigj && priv->xsaw_secondary > 1) - do_recal = true; - priv->xbigj = 0; - priv->xsaw_secondary = 0; - } - - if (avy > recalib_delta || - (avy > recalib_delta / 2 && ((avy / 4) > priv->ylast))) { - psmouse_warn(psmouse, "detected %dpx jump in y\n", y); - priv->ybigj = avy; - } else if (approx_half(avy, priv->ybigj)) { - psmouse_warn(psmouse, "detected secondary %dpx jump in y\n", y); - priv->ybigj = avy; - priv->ysaw_secondary++; - } else { - if (priv->ybigj && priv->ysaw_secondary > 1) - do_recal = true; - priv->ybigj = 0; - priv->ysaw_secondary = 0; - } - - priv->xlast = avx; - priv->ylast = avy; - - if (do_recal && jumpy_delay) { - psmouse_warn(psmouse, "scheduling recalibration\n"); - psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(jumpy_delay)); - } - - return priv->xbigj || priv->ybigj; -} - -static void hgpk_reset_spew_detection(struct hgpk_data *priv) -{ - priv->spew_count = 0; - priv->dupe_count = 0; - priv->x_tally = 0; - priv->y_tally = 0; - priv->spew_flag = NO_SPEW; -} - -static void hgpk_reset_hack_state(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - - priv->abs_x = priv->abs_y = -1; - priv->xlast = priv->ylast = ILLEGAL_XY; - priv->xbigj = priv->ybigj = 0; - priv->xsaw_secondary = priv->ysaw_secondary = 0; - hgpk_reset_spew_detection(priv); -} - -/* - * We have no idea why this particular hardware bug occurs. The touchpad - * will randomly start spewing packets without anything touching the - * pad. This wouldn't necessarily be bad, but it's indicative of a - * severely miscalibrated pad; attempting to use the touchpad while it's - * spewing means the cursor will jump all over the place, and act "drunk". - * - * The packets that are spewed tend to all have deltas between -2 and 2, and - * the cursor will move around without really going very far. It will - * tend to end up in the same location; if we tally up the changes over - * 100 packets, we end up w/ a final delta of close to 0. This happens - * pretty regularly when the touchpad is spewing, and is pretty hard to - * manually trigger (at least for *my* fingers). So, it makes a perfect - * scheme for detecting spews. - */ -static void hgpk_spewing_hack(struct psmouse *psmouse, - int l, int r, int x, int y) -{ - struct hgpk_data *priv = psmouse->private; - - /* ignore button press packets; many in a row could trigger - * a false-positive! */ - if (l || r) - return; - - /* don't track spew if the workaround feature has been turned off */ - if (!spew_delay) - return; - - if (abs(x) > 3 || abs(y) > 3) { - /* no spew, or spew ended */ - hgpk_reset_spew_detection(priv); - return; - } - - /* Keep a tally of the overall delta to the cursor position caused by - * the spew */ - priv->x_tally += x; - priv->y_tally += y; - - switch (priv->spew_flag) { - case NO_SPEW: - /* we're not spewing, but this packet might be the start */ - priv->spew_flag = MAYBE_SPEWING; - - fallthrough; - - case MAYBE_SPEWING: - priv->spew_count++; - - if (priv->spew_count < SPEW_WATCH_COUNT) - break; - - /* excessive spew detected, request recalibration */ - priv->spew_flag = SPEW_DETECTED; - - fallthrough; - - case SPEW_DETECTED: - /* only recalibrate when the overall delta to the cursor - * is really small. if the spew is causing significant cursor - * movement, it is probably a case of the user moving the - * cursor very slowly across the screen. */ - if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) { - psmouse_warn(psmouse, "packet spew detected (%d,%d)\n", - priv->x_tally, priv->y_tally); - priv->spew_flag = RECALIBRATING; - psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(spew_delay)); - } - - break; - case RECALIBRATING: - /* we already detected a spew and requested a recalibration, - * just wait for the queue to kick into action. */ - break; - } -} - -/* - * HGPK Mouse Mode format (standard mouse format, sans middle button) - * - * byte 0: y-over x-over y-neg x-neg 1 0 swr swl - * byte 1: x7 x6 x5 x4 x3 x2 x1 x0 - * byte 2: y7 y6 y5 y4 y3 y2 y1 y0 - * - * swr/swl are the left/right buttons. - * x-neg/y-neg are the x and y delta negative bits - * x-over/y-over are the x and y overflow bits - * - * --- - * - * HGPK Advanced Mode - single-mode format - * - * byte 0(PT): 1 1 0 0 1 1 1 1 - * byte 0(GS): 1 1 1 1 1 1 1 1 - * byte 1: 0 x6 x5 x4 x3 x2 x1 x0 - * byte 2(PT): 0 0 x9 x8 x7 ? pt-dsw 0 - * byte 2(GS): 0 x10 x9 x8 x7 ? gs-dsw pt-dsw - * byte 3: 0 y9 y8 y7 1 0 swr swl - * byte 4: 0 y6 y5 y4 y3 y2 y1 y0 - * byte 5: 0 z6 z5 z4 z3 z2 z1 z0 - * - * ?'s are not defined in the protocol spec, may vary between models. - * - * swr/swl are the left/right buttons. - * - * pt-dsw/gs-dsw indicate that the pt/gs sensor is detecting a - * pen/finger - */ -static bool hgpk_is_byte_valid(struct psmouse *psmouse, unsigned char *packet) -{ - struct hgpk_data *priv = psmouse->private; - int pktcnt = psmouse->pktcnt; - bool valid; - - switch (priv->mode) { - case HGPK_MODE_MOUSE: - valid = (packet[0] & 0x0C) == 0x08; - break; - - case HGPK_MODE_GLIDESENSOR: - valid = pktcnt == 1 ? - packet[0] == HGPK_GS : !(packet[pktcnt - 1] & 0x80); - break; - - case HGPK_MODE_PENTABLET: - valid = pktcnt == 1 ? - packet[0] == HGPK_PT : !(packet[pktcnt - 1] & 0x80); - break; - - default: - valid = false; - break; - } - - if (!valid) - psmouse_dbg(psmouse, - "bad data, mode %d (%d) %*ph\n", - priv->mode, pktcnt, 6, psmouse->packet); - - return valid; -} - -static void hgpk_process_advanced_packet(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - struct input_dev *idev = psmouse->dev; - unsigned char *packet = psmouse->packet; - int down = !!(packet[2] & 2); - int left = !!(packet[3] & 1); - int right = !!(packet[3] & 2); - int x = packet[1] | ((packet[2] & 0x78) << 4); - int y = packet[4] | ((packet[3] & 0x70) << 3); - - if (priv->mode == HGPK_MODE_GLIDESENSOR) { - int pt_down = !!(packet[2] & 1); - int finger_down = !!(packet[2] & 2); - int z = packet[5]; - - input_report_abs(idev, ABS_PRESSURE, z); - if (tpdebug) - psmouse_dbg(psmouse, "pd=%d fd=%d z=%d", - pt_down, finger_down, z); - } else { - /* - * PenTablet mode does not report pressure, so we don't - * report it here - */ - if (tpdebug) - psmouse_dbg(psmouse, "pd=%d ", down); - } - - if (tpdebug) - psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", - left, right, x, y); - - input_report_key(idev, BTN_TOUCH, down); - input_report_key(idev, BTN_LEFT, left); - input_report_key(idev, BTN_RIGHT, right); - - /* - * If this packet says that the finger was removed, reset our position - * tracking so that we don't erroneously detect a jump on next press. - */ - if (!down) { - hgpk_reset_hack_state(psmouse); - goto done; - } - - /* - * Weed out duplicate packets (we get quite a few, and they mess up - * our jump detection) - */ - if (x == priv->abs_x && y == priv->abs_y) { - if (++priv->dupe_count > SPEW_WATCH_COUNT) { - if (tpdebug) - psmouse_dbg(psmouse, "hard spew detected\n"); - priv->spew_flag = RECALIBRATING; - psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(spew_delay)); - } - goto done; - } - - /* not a duplicate, continue with position reporting */ - priv->dupe_count = 0; - - /* Don't apply hacks in PT mode, it seems reliable */ - if (priv->mode != HGPK_MODE_PENTABLET && priv->abs_x != -1) { - int x_diff = priv->abs_x - x; - int y_diff = priv->abs_y - y; - if (hgpk_discard_decay_hack(psmouse, x_diff, y_diff)) { - if (tpdebug) - psmouse_dbg(psmouse, "discarding\n"); - goto done; - } - hgpk_spewing_hack(psmouse, left, right, x_diff, y_diff); - } - - input_report_abs(idev, ABS_X, x); - input_report_abs(idev, ABS_Y, y); - priv->abs_x = x; - priv->abs_y = y; - -done: - input_sync(idev); -} - -static void hgpk_process_simple_packet(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - unsigned char *packet = psmouse->packet; - int left = packet[0] & 1; - int right = (packet[0] >> 1) & 1; - int x = packet[1] - ((packet[0] << 4) & 0x100); - int y = ((packet[0] << 3) & 0x100) - packet[2]; - - if (packet[0] & 0xc0) - psmouse_dbg(psmouse, - "overflow -- 0x%02x 0x%02x 0x%02x\n", - packet[0], packet[1], packet[2]); - - if (hgpk_discard_decay_hack(psmouse, x, y)) { - if (tpdebug) - psmouse_dbg(psmouse, "discarding\n"); - return; - } - - hgpk_spewing_hack(psmouse, left, right, x, y); - - if (tpdebug) - psmouse_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", - left, right, x, y); - - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - - input_report_rel(dev, REL_X, x); - input_report_rel(dev, REL_Y, y); - - input_sync(dev); -} - -static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - - if (!hgpk_is_byte_valid(psmouse, psmouse->packet)) - return PSMOUSE_BAD_DATA; - - if (psmouse->pktcnt >= psmouse->pktsize) { - if (priv->mode == HGPK_MODE_MOUSE) - hgpk_process_simple_packet(psmouse); - else - hgpk_process_advanced_packet(psmouse); - return PSMOUSE_FULL_PACKET; - } - - if (priv->recalib_window) { - if (time_before(jiffies, priv->recalib_window)) { - /* - * ugh, got a packet inside our recalibration - * window, schedule another recalibration. - */ - psmouse_dbg(psmouse, - "packet inside calibration window, queueing another recalibration\n"); - psmouse_queue_work(psmouse, &priv->recalib_wq, - msecs_to_jiffies(post_interrupt_delay)); - } - priv->recalib_window = 0; - } - - return PSMOUSE_GOOD_DATA; -} - -static int hgpk_select_mode(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - struct hgpk_data *priv = psmouse->private; - int i; - int cmd; - - /* - * 4 disables to enable advanced mode - * then 3 0xf2 bytes as the preamble for GS/PT selection - */ - const int advanced_init[] = { - PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE, - PSMOUSE_CMD_DISABLE, PSMOUSE_CMD_DISABLE, - 0xf2, 0xf2, 0xf2, - }; - - switch (priv->mode) { - case HGPK_MODE_MOUSE: - psmouse->pktsize = 3; - break; - - case HGPK_MODE_GLIDESENSOR: - case HGPK_MODE_PENTABLET: - psmouse->pktsize = 6; - - /* Switch to 'Advanced mode.', four disables in a row. */ - for (i = 0; i < ARRAY_SIZE(advanced_init); i++) - if (ps2_command(ps2dev, NULL, advanced_init[i])) - return -EIO; - - /* select between GlideSensor (mouse) or PenTablet */ - cmd = priv->mode == HGPK_MODE_GLIDESENSOR ? - PSMOUSE_CMD_SETSCALE11 : PSMOUSE_CMD_SETSCALE21; - - if (ps2_command(ps2dev, NULL, cmd)) - return -EIO; - break; - - default: - return -EINVAL; - } - - return 0; -} - -static void hgpk_setup_input_device(struct input_dev *input, - struct input_dev *old_input, - enum hgpk_mode mode) -{ - if (old_input) { - input->name = old_input->name; - input->phys = old_input->phys; - input->id = old_input->id; - input->dev.parent = old_input->dev.parent; - } - - memset(input->evbit, 0, sizeof(input->evbit)); - memset(input->relbit, 0, sizeof(input->relbit)); - memset(input->keybit, 0, sizeof(input->keybit)); - - /* All modes report left and right buttons */ - __set_bit(EV_KEY, input->evbit); - __set_bit(BTN_LEFT, input->keybit); - __set_bit(BTN_RIGHT, input->keybit); - - switch (mode) { - case HGPK_MODE_MOUSE: - __set_bit(EV_REL, input->evbit); - __set_bit(REL_X, input->relbit); - __set_bit(REL_Y, input->relbit); - break; - - case HGPK_MODE_GLIDESENSOR: - __set_bit(BTN_TOUCH, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - - __set_bit(EV_ABS, input->evbit); - - /* GlideSensor has pressure sensor, PenTablet does not */ - input_set_abs_params(input, ABS_PRESSURE, 0, 15, 0, 0); - - /* From device specs */ - input_set_abs_params(input, ABS_X, 0, 399, 0, 0); - input_set_abs_params(input, ABS_Y, 0, 290, 0, 0); - - /* Calculated by hand based on usable size (52mm x 38mm) */ - input_abs_set_res(input, ABS_X, 8); - input_abs_set_res(input, ABS_Y, 8); - break; - - case HGPK_MODE_PENTABLET: - __set_bit(BTN_TOUCH, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - - __set_bit(EV_ABS, input->evbit); - - /* From device specs */ - input_set_abs_params(input, ABS_X, 0, 999, 0, 0); - input_set_abs_params(input, ABS_Y, 5, 239, 0, 0); - - /* Calculated by hand based on usable size (156mm x 38mm) */ - input_abs_set_res(input, ABS_X, 6); - input_abs_set_res(input, ABS_Y, 8); - break; - - default: - BUG(); - } -} - -static int hgpk_reset_device(struct psmouse *psmouse, bool recalibrate) -{ - int err; - - psmouse_reset(psmouse); - - if (recalibrate) { - struct ps2dev *ps2dev = &psmouse->ps2dev; - - /* send the recalibrate request */ - if (ps2_command(ps2dev, NULL, 0xf5) || - ps2_command(ps2dev, NULL, 0xf5) || - ps2_command(ps2dev, NULL, 0xe6) || - ps2_command(ps2dev, NULL, 0xf5)) { - return -1; - } - - /* according to ALPS, 150mS is required for recalibration */ - msleep(150); - } - - err = hgpk_select_mode(psmouse); - if (err) { - psmouse_err(psmouse, "failed to select mode\n"); - return err; - } - - hgpk_reset_hack_state(psmouse); - - return 0; -} - -static int hgpk_force_recalibrate(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - int err; - - /* C-series touchpads added the recalibrate command */ - if (psmouse->model < HGPK_MODEL_C) - return 0; - - if (!autorecal) { - psmouse_dbg(psmouse, "recalibration disabled, ignoring\n"); - return 0; - } - - psmouse_dbg(psmouse, "recalibrating touchpad..\n"); - - /* we don't want to race with the irq handler, nor with resyncs */ - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - /* start by resetting the device */ - err = hgpk_reset_device(psmouse, true); - if (err) - return err; - - /* - * XXX: If a finger is down during this delay, recalibration will - * detect capacitance incorrectly. This is a hardware bug, and - * we don't have a good way to deal with it. The 2s window stuff - * (below) is our best option for now. - */ - if (psmouse_activate(psmouse)) - return -1; - - if (tpdebug) - psmouse_dbg(psmouse, "touchpad reactivated\n"); - - /* - * If we get packets right away after recalibrating, it's likely - * that a finger was on the touchpad. If so, it's probably - * miscalibrated, so we optionally schedule another. - */ - if (recal_guard_time) - priv->recalib_window = jiffies + - msecs_to_jiffies(recal_guard_time); - - return 0; -} - -/* - * This puts the touchpad in a power saving mode; according to ALPS, current - * consumption goes down to 50uA after running this. To turn power back on, - * we drive MS-DAT low. Measuring with a 1mA resolution ammeter says that - * the current on the SUS_3.3V rail drops from 3mA or 4mA to 0 when we do this. - * - * We have no formal spec that details this operation -- the low-power - * sequence came from a long-lost email trail. - */ -static int hgpk_toggle_powersave(struct psmouse *psmouse, int enable) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int timeo; - int err; - - /* Added on D-series touchpads */ - if (psmouse->model < HGPK_MODEL_D) - return 0; - - if (enable) { - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - /* - * Sending a byte will drive MS-DAT low; this will wake up - * the controller. Once we get an ACK back from it, it - * means we can continue with the touchpad re-init. ALPS - * tells us that 1s should be long enough, so set that as - * the upper bound. (in practice, it takes about 3 loops.) - */ - for (timeo = 20; timeo > 0; timeo--) { - if (!ps2_sendbyte(ps2dev, PSMOUSE_CMD_DISABLE, 20)) - break; - msleep(25); - } - - err = hgpk_reset_device(psmouse, false); - if (err) { - psmouse_err(psmouse, "Failed to reset device!\n"); - return err; - } - - /* should be all set, enable the touchpad */ - psmouse_activate(psmouse); - psmouse_dbg(psmouse, "Touchpad powered up.\n"); - } else { - psmouse_dbg(psmouse, "Powering off touchpad.\n"); - - if (ps2_command(ps2dev, NULL, 0xec) || - ps2_command(ps2dev, NULL, 0xec) || - ps2_command(ps2dev, NULL, 0xea)) { - return -1; - } - - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - - /* probably won't see an ACK, the touchpad will be off */ - ps2_sendbyte(ps2dev, 0xec, 20); - } - - return 0; -} - -static int hgpk_poll(struct psmouse *psmouse) -{ - /* We can't poll, so always return failure. */ - return -1; -} - -static int hgpk_reconnect(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - - /* - * During suspend/resume the ps2 rails remain powered. We don't want - * to do a reset because it's flush data out of buffers; however, - * earlier prototypes (B1) had some brokenness that required a reset. - */ - if (olpc_board_at_least(olpc_board(0xb2))) - if (psmouse->ps2dev.serio->dev.power.power_state.event != - PM_EVENT_ON) - return 0; - - priv->powered = 1; - return hgpk_reset_device(psmouse, false); -} - -static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf) -{ - struct hgpk_data *priv = psmouse->private; - - return sprintf(buf, "%d\n", priv->powered); -} - -static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data, - const char *buf, size_t count) -{ - struct hgpk_data *priv = psmouse->private; - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (value != priv->powered) { - /* - * hgpk_toggle_power will deal w/ state so - * we're not racing w/ irq - */ - err = hgpk_toggle_powersave(psmouse, value); - if (!err) - priv->powered = value; - } - - return err ? err : count; -} - -__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL, - hgpk_show_powered, hgpk_set_powered, false); - -static ssize_t attr_show_mode(struct psmouse *psmouse, void *data, char *buf) -{ - struct hgpk_data *priv = psmouse->private; - - return sprintf(buf, "%s\n", hgpk_mode_names[priv->mode]); -} - -static ssize_t attr_set_mode(struct psmouse *psmouse, void *data, - const char *buf, size_t len) -{ - struct hgpk_data *priv = psmouse->private; - enum hgpk_mode old_mode = priv->mode; - enum hgpk_mode new_mode = hgpk_mode_from_name(buf, len); - struct input_dev *old_dev = psmouse->dev; - struct input_dev *new_dev; - int err; - - if (new_mode == HGPK_MODE_INVALID) - return -EINVAL; - - if (old_mode == new_mode) - return len; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - /* Switch device into the new mode */ - priv->mode = new_mode; - err = hgpk_reset_device(psmouse, false); - if (err) - goto err_try_restore; - - hgpk_setup_input_device(new_dev, old_dev, new_mode); - - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - err = input_register_device(new_dev); - if (err) - goto err_try_restore; - - psmouse->dev = new_dev; - input_unregister_device(old_dev); - - return len; - -err_try_restore: - input_free_device(new_dev); - priv->mode = old_mode; - hgpk_reset_device(psmouse, false); - - return err; -} - -PSMOUSE_DEFINE_ATTR(hgpk_mode, S_IWUSR | S_IRUGO, NULL, - attr_show_mode, attr_set_mode); - -static ssize_t hgpk_trigger_recal_show(struct psmouse *psmouse, - void *data, char *buf) -{ - return -EINVAL; -} - -static ssize_t hgpk_trigger_recal(struct psmouse *psmouse, void *data, - const char *buf, size_t count) -{ - struct hgpk_data *priv = psmouse->private; - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value != 1) - return -EINVAL; - - /* - * We queue work instead of doing recalibration right here - * to avoid adding locking to hgpk_force_recalibrate() - * since workqueue provides serialization. - */ - psmouse_queue_work(psmouse, &priv->recalib_wq, 0); - return count; -} - -__PSMOUSE_DEFINE_ATTR(recalibrate, S_IWUSR | S_IRUGO, NULL, - hgpk_trigger_recal_show, hgpk_trigger_recal, false); - -static void hgpk_disconnect(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_powered.dattr); - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_hgpk_mode.dattr); - - if (psmouse->model >= HGPK_MODEL_C) - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_recalibrate.dattr); - - psmouse_reset(psmouse); - kfree(priv); -} - -static void hgpk_recalib_work(struct work_struct *work) -{ - struct delayed_work *w = to_delayed_work(work); - struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq); - struct psmouse *psmouse = priv->psmouse; - - if (hgpk_force_recalibrate(psmouse)) - psmouse_err(psmouse, "recalibration failed!\n"); -} - -static int hgpk_register(struct psmouse *psmouse) -{ - struct hgpk_data *priv = psmouse->private; - int err; - - /* register handlers */ - psmouse->protocol_handler = hgpk_process_byte; - psmouse->poll = hgpk_poll; - psmouse->disconnect = hgpk_disconnect; - psmouse->reconnect = hgpk_reconnect; - - /* Disable the idle resync. */ - psmouse->resync_time = 0; - /* Reset after a lot of bad bytes. */ - psmouse->resetafter = 1024; - - hgpk_setup_input_device(psmouse->dev, NULL, priv->mode); - - err = device_create_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_powered.dattr); - if (err) { - psmouse_err(psmouse, "Failed creating 'powered' sysfs node\n"); - return err; - } - - err = device_create_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_hgpk_mode.dattr); - if (err) { - psmouse_err(psmouse, - "Failed creating 'hgpk_mode' sysfs node\n"); - goto err_remove_powered; - } - - /* C-series touchpads added the recalibrate command */ - if (psmouse->model >= HGPK_MODEL_C) { - err = device_create_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_recalibrate.dattr); - if (err) { - psmouse_err(psmouse, - "Failed creating 'recalibrate' sysfs node\n"); - goto err_remove_mode; - } - } - - return 0; - -err_remove_mode: - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_hgpk_mode.dattr); -err_remove_powered: - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_powered.dattr); - return err; -} - -int hgpk_init(struct psmouse *psmouse) -{ - struct hgpk_data *priv; - int err; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - err = -ENOMEM; - goto alloc_fail; - } - - psmouse->private = priv; - - priv->psmouse = psmouse; - priv->powered = true; - priv->mode = hgpk_default_mode; - INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work); - - err = hgpk_reset_device(psmouse, false); - if (err) - goto init_fail; - - err = hgpk_register(psmouse); - if (err) - goto init_fail; - - return 0; - -init_fail: - kfree(priv); -alloc_fail: - return err; -} - -static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[3]; - - /* E7, E7, E7, E9 gets us a 3 byte identifier */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || - ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { - return -EIO; - } - - psmouse_dbg(psmouse, "ID: %*ph\n", 3, param); - - /* HGPK signature: 0x67, 0x00, 0x<model> */ - if (param[0] != 0x67 || param[1] != 0x00) - return -ENODEV; - - psmouse_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]); - - return param[2]; -} - -int hgpk_detect(struct psmouse *psmouse, bool set_properties) -{ - int version; - - version = hgpk_get_model(psmouse); - if (version < 0) - return version; - - if (set_properties) { - psmouse->vendor = "ALPS"; - psmouse->name = "HGPK"; - psmouse->model = version; - } - - return 0; -} - -void hgpk_module_init(void) -{ - hgpk_default_mode = hgpk_mode_from_name(hgpk_mode_name, - strlen(hgpk_mode_name)); - if (hgpk_default_mode == HGPK_MODE_INVALID) { - hgpk_default_mode = HGPK_MODE_MOUSE; - strscpy(hgpk_mode_name, hgpk_mode_names[HGPK_MODE_MOUSE], - sizeof(hgpk_mode_name)); - } -} diff --git a/drivers/input/mouse/hgpk.h b/drivers/input/mouse/hgpk.h deleted file mode 100644 index ce041591f1a8..000000000000 --- a/drivers/input/mouse/hgpk.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * OLPC HGPK (XO-1) touchpad PS/2 mouse driver - */ - -#ifndef _HGPK_H -#define _HGPK_H - -#define HGPK_GS 0xff /* The GlideSensor */ -#define HGPK_PT 0xcf /* The PenTablet */ - -enum hgpk_model_t { - HGPK_MODEL_PREA = 0x0a, /* pre-B1s */ - HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */ - HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */ - HGPK_MODEL_C = 0x3c, - HGPK_MODEL_D = 0x50, /* C1, mass production */ -}; - -enum hgpk_spew_flag { - NO_SPEW, - MAYBE_SPEWING, - SPEW_DETECTED, - RECALIBRATING, -}; - -#define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */ - -enum hgpk_mode { - HGPK_MODE_MOUSE, - HGPK_MODE_GLIDESENSOR, - HGPK_MODE_PENTABLET, - HGPK_MODE_INVALID -}; - -struct hgpk_data { - struct psmouse *psmouse; - enum hgpk_mode mode; - bool powered; - enum hgpk_spew_flag spew_flag; - int spew_count, x_tally, y_tally; /* spew detection */ - unsigned long recalib_window; - struct delayed_work recalib_wq; - int abs_x, abs_y; - int dupe_count; - int xbigj, ybigj, xlast, ylast; /* jumpiness detection */ - int xsaw_secondary, ysaw_secondary; /* jumpiness detection */ -}; - -int hgpk_detect(struct psmouse *psmouse, bool set_properties); -int hgpk_init(struct psmouse *psmouse); - -#ifdef CONFIG_MOUSE_PS2_OLPC -void hgpk_module_init(void); -#else -static inline void hgpk_module_init(void) -{ -} -#endif - -#endif diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c deleted file mode 100644 index 401d8bff8e84..000000000000 --- a/drivers/input/mouse/inport.c +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 1999-2001 Vojtech Pavlik - * - * Based on the work of: - * Teemu Rantanen Derrick Cole - * Peter Cervasio Christoph Niemann - * Philip Blundell Russell King - * Bob Harris - */ - -/* - * Inport (ATI XL and Microsoft) busmouse driver for Linux - */ - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/input.h> - -#include <asm/io.h> -#include <asm/irq.h> - -MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); -MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver"); -MODULE_LICENSE("GPL"); - -#define INPORT_BASE 0x23c -#define INPORT_EXTENT 4 - -#define INPORT_CONTROL_PORT INPORT_BASE + 0 -#define INPORT_DATA_PORT INPORT_BASE + 1 -#define INPORT_SIGNATURE_PORT INPORT_BASE + 2 - -#define INPORT_REG_BTNS 0x00 -#define INPORT_REG_X 0x01 -#define INPORT_REG_Y 0x02 -#define INPORT_REG_MODE 0x07 -#define INPORT_RESET 0x80 - -#ifdef CONFIG_MOUSE_ATIXL -#define INPORT_NAME "ATI XL Mouse" -#define INPORT_VENDOR 0x0002 -#define INPORT_SPEED_30HZ 0x01 -#define INPORT_SPEED_50HZ 0x02 -#define INPORT_SPEED_100HZ 0x03 -#define INPORT_SPEED_200HZ 0x04 -#define INPORT_MODE_BASE INPORT_SPEED_100HZ -#define INPORT_MODE_IRQ 0x08 -#else -#define INPORT_NAME "Microsoft InPort Mouse" -#define INPORT_VENDOR 0x0001 -#define INPORT_MODE_BASE 0x10 -#define INPORT_MODE_IRQ 0x01 -#endif -#define INPORT_MODE_HOLD 0x20 - -#define INPORT_IRQ 5 - -static int inport_irq = INPORT_IRQ; -module_param_hw_named(irq, inport_irq, uint, irq, 0); -MODULE_PARM_DESC(irq, "IRQ number (5=default)"); - -static struct input_dev *inport_dev; - -static irqreturn_t inport_interrupt(int irq, void *dev_id) -{ - unsigned char buttons; - - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - outb(INPORT_REG_X, INPORT_CONTROL_PORT); - input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT)); - - outb(INPORT_REG_Y, INPORT_CONTROL_PORT); - input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT)); - - outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT); - buttons = inb(INPORT_DATA_PORT); - - input_report_key(inport_dev, BTN_MIDDLE, buttons & 1); - input_report_key(inport_dev, BTN_LEFT, buttons & 2); - input_report_key(inport_dev, BTN_RIGHT, buttons & 4); - - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - input_sync(inport_dev); - return IRQ_HANDLED; -} - -static int inport_open(struct input_dev *dev) -{ - if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL)) - return -EBUSY; - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT); - - return 0; -} - -static void inport_close(struct input_dev *dev) -{ - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_BASE, INPORT_DATA_PORT); - free_irq(inport_irq, NULL); -} - -static int __init inport_init(void) -{ - unsigned char a, b, c; - int err; - - if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) { - printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE); - return -EBUSY; - } - - a = inb(INPORT_SIGNATURE_PORT); - b = inb(INPORT_SIGNATURE_PORT); - c = inb(INPORT_SIGNATURE_PORT); - if (a == b || a != c) { - printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE); - err = -ENODEV; - goto err_release_region; - } - - inport_dev = input_allocate_device(); - if (!inport_dev) { - printk(KERN_ERR "inport.c: Not enough memory for input device\n"); - err = -ENOMEM; - goto err_release_region; - } - - inport_dev->name = INPORT_NAME; - inport_dev->phys = "isa023c/input0"; - inport_dev->id.bustype = BUS_ISA; - inport_dev->id.vendor = INPORT_VENDOR; - inport_dev->id.product = 0x0001; - inport_dev->id.version = 0x0100; - - inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); - inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - - inport_dev->open = inport_open; - inport_dev->close = inport_close; - - outb(INPORT_RESET, INPORT_CONTROL_PORT); - outb(INPORT_REG_MODE, INPORT_CONTROL_PORT); - outb(INPORT_MODE_BASE, INPORT_DATA_PORT); - - err = input_register_device(inport_dev); - if (err) - goto err_free_dev; - - return 0; - - err_free_dev: - input_free_device(inport_dev); - err_release_region: - release_region(INPORT_BASE, INPORT_EXTENT); - - return err; -} - -static void __exit inport_exit(void) -{ - input_unregister_device(inport_dev); - release_region(INPORT_BASE, INPORT_EXTENT); -} - -module_init(inport_init); -module_exit(inport_exit); diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 7147dacc404f..ef11b7b19833 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -273,14 +273,14 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) struct lifebook_data *priv; int error = -ENOMEM; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); dev2 = input_allocate_device(); if (!priv || !dev2) goto err_out; priv->dev2 = dev2; - snprintf(priv->phys, sizeof(priv->phys), - "%s/input1", psmouse->ps2dev.serio->phys); + scnprintf(priv->phys, sizeof(priv->phys), + "%s/input1", psmouse->ps2dev.serio->phys); dev2->phys = priv->phys; dev2->name = "LBPS/2 Fujitsu Lifebook Touchpad"; diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c deleted file mode 100644 index 0aab63dbc30a..000000000000 --- a/drivers/input/mouse/logibm.c +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 1999-2001 Vojtech Pavlik - * - * Based on the work of: - * James Banks Matthew Dillon - * David Giller Nathan Laredo - * Linus Torvalds Johan Myreen - * Cliff Matthews Philip Blundell - * Russell King - */ - -/* - * Logitech Bus Mouse Driver for Linux - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/input.h> -#include <linux/interrupt.h> - -#include <asm/io.h> -#include <asm/irq.h> - -MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); -MODULE_DESCRIPTION("Logitech busmouse driver"); -MODULE_LICENSE("GPL"); - -#define LOGIBM_BASE 0x23c -#define LOGIBM_EXTENT 4 - -#define LOGIBM_DATA_PORT LOGIBM_BASE + 0 -#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1 -#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2 -#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3 - -#define LOGIBM_ENABLE_IRQ 0x00 -#define LOGIBM_DISABLE_IRQ 0x10 -#define LOGIBM_READ_X_LOW 0x80 -#define LOGIBM_READ_X_HIGH 0xa0 -#define LOGIBM_READ_Y_LOW 0xc0 -#define LOGIBM_READ_Y_HIGH 0xe0 - -#define LOGIBM_DEFAULT_MODE 0x90 -#define LOGIBM_CONFIG_BYTE 0x91 -#define LOGIBM_SIGNATURE_BYTE 0xa5 - -#define LOGIBM_IRQ 5 - -static int logibm_irq = LOGIBM_IRQ; -module_param_hw_named(irq, logibm_irq, uint, irq, 0); -MODULE_PARM_DESC(irq, "IRQ number (5=default)"); - -static struct input_dev *logibm_dev; - -static irqreturn_t logibm_interrupt(int irq, void *dev_id) -{ - char dx, dy; - unsigned char buttons; - - outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT); - dx = (inb(LOGIBM_DATA_PORT) & 0xf); - outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT); - dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4; - outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT); - dy = (inb(LOGIBM_DATA_PORT) & 0xf); - outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT); - buttons = inb(LOGIBM_DATA_PORT); - dy |= (buttons & 0xf) << 4; - buttons = ~buttons >> 5; - - input_report_rel(logibm_dev, REL_X, dx); - input_report_rel(logibm_dev, REL_Y, dy); - input_report_key(logibm_dev, BTN_RIGHT, buttons & 1); - input_report_key(logibm_dev, BTN_MIDDLE, buttons & 2); - input_report_key(logibm_dev, BTN_LEFT, buttons & 4); - input_sync(logibm_dev); - - outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); - return IRQ_HANDLED; -} - -static int logibm_open(struct input_dev *dev) -{ - if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) { - printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq); - return -EBUSY; - } - outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT); - return 0; -} - -static void logibm_close(struct input_dev *dev) -{ - outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - free_irq(logibm_irq, NULL); -} - -static int __init logibm_init(void) -{ - int err; - - if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) { - printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE); - return -EBUSY; - } - - outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT); - outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT); - udelay(100); - - if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) { - printk(KERN_INFO "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE); - err = -ENODEV; - goto err_release_region; - } - - outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT); - outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT); - - logibm_dev = input_allocate_device(); - if (!logibm_dev) { - printk(KERN_ERR "logibm.c: Not enough memory for input device\n"); - err = -ENOMEM; - goto err_release_region; - } - - logibm_dev->name = "Logitech bus mouse"; - logibm_dev->phys = "isa023c/input0"; - logibm_dev->id.bustype = BUS_ISA; - logibm_dev->id.vendor = 0x0003; - logibm_dev->id.product = 0x0001; - logibm_dev->id.version = 0x0100; - - logibm_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - logibm_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); - logibm_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - - logibm_dev->open = logibm_open; - logibm_dev->close = logibm_close; - - err = input_register_device(logibm_dev); - if (err) - goto err_free_dev; - - return 0; - - err_free_dev: - input_free_device(logibm_dev); - err_release_region: - release_region(LOGIBM_BASE, LOGIBM_EXTENT); - - return err; -} - -static void __exit logibm_exit(void) -{ - input_unregister_device(logibm_dev); - release_region(LOGIBM_BASE, LOGIBM_EXTENT); -} - -module_init(logibm_init); -module_exit(logibm_exit); diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c index baef4be14b54..c99f7e234219 100644 --- a/drivers/input/mouse/maplemouse.c +++ b/drivers/input/mouse/maplemouse.c @@ -73,7 +73,7 @@ static int probe_maple_mouse(struct device *dev) struct input_dev *input_dev; struct dc_mouse *mse; - mse = kzalloc(sizeof(*mse), GFP_KERNEL); + mse = kzalloc_obj(*mse); if (!mse) { error = -ENOMEM; goto fail; diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c deleted file mode 100644 index efa58049f746..000000000000 --- a/drivers/input/mouse/pc110pad.c +++ /dev/null @@ -1,160 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * Based on the work of: - * Alan Cox Robin O'Leary - */ - -/* - * IBM PC110 touchpad driver for Linux - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/input.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/delay.h> - -#include <asm/io.h> -#include <asm/irq.h> - -MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); -MODULE_DESCRIPTION("IBM PC110 touchpad driver"); -MODULE_LICENSE("GPL"); - -#define PC110PAD_OFF 0x30 -#define PC110PAD_ON 0x38 - -static int pc110pad_irq = 10; -static int pc110pad_io = 0x15e0; - -static struct input_dev *pc110pad_dev; -static int pc110pad_data[3]; -static int pc110pad_count; - -static irqreturn_t pc110pad_interrupt(int irq, void *ptr) -{ - int value = inb_p(pc110pad_io); - int handshake = inb_p(pc110pad_io + 2); - - outb(handshake | 1, pc110pad_io + 2); - udelay(2); - outb(handshake & ~1, pc110pad_io + 2); - udelay(2); - inb_p(0x64); - - pc110pad_data[pc110pad_count++] = value; - - if (pc110pad_count < 3) - return IRQ_HANDLED; - - input_report_key(pc110pad_dev, BTN_TOUCH, - pc110pad_data[0] & 0x01); - input_report_abs(pc110pad_dev, ABS_X, - pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100)); - input_report_abs(pc110pad_dev, ABS_Y, - pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80)); - input_sync(pc110pad_dev); - - pc110pad_count = 0; - return IRQ_HANDLED; -} - -static void pc110pad_close(struct input_dev *dev) -{ - outb(PC110PAD_OFF, pc110pad_io + 2); -} - -static int pc110pad_open(struct input_dev *dev) -{ - pc110pad_interrupt(0, NULL); - pc110pad_interrupt(0, NULL); - pc110pad_interrupt(0, NULL); - outb(PC110PAD_ON, pc110pad_io + 2); - pc110pad_count = 0; - - return 0; -} - -/* - * We try to avoid enabling the hardware if it's not - * there, but we don't know how to test. But we do know - * that the PC110 is not a PCI system. So if we find any - * PCI devices in the machine, we don't have a PC110. - */ -static int __init pc110pad_init(void) -{ - int err; - - if (!no_pci_devices()) - return -ENODEV; - - if (!request_region(pc110pad_io, 4, "pc110pad")) { - printk(KERN_ERR "pc110pad: I/O area %#x-%#x in use.\n", - pc110pad_io, pc110pad_io + 4); - return -EBUSY; - } - - outb(PC110PAD_OFF, pc110pad_io + 2); - - if (request_irq(pc110pad_irq, pc110pad_interrupt, 0, "pc110pad", NULL)) { - printk(KERN_ERR "pc110pad: Unable to get irq %d.\n", pc110pad_irq); - err = -EBUSY; - goto err_release_region; - } - - pc110pad_dev = input_allocate_device(); - if (!pc110pad_dev) { - printk(KERN_ERR "pc110pad: Not enough memory.\n"); - err = -ENOMEM; - goto err_free_irq; - } - - pc110pad_dev->name = "IBM PC110 TouchPad"; - pc110pad_dev->phys = "isa15e0/input0"; - pc110pad_dev->id.bustype = BUS_ISA; - pc110pad_dev->id.vendor = 0x0003; - pc110pad_dev->id.product = 0x0001; - pc110pad_dev->id.version = 0x0100; - - pc110pad_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - pc110pad_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y); - pc110pad_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - - input_abs_set_max(pc110pad_dev, ABS_X, 0x1ff); - input_abs_set_max(pc110pad_dev, ABS_Y, 0x0ff); - - pc110pad_dev->open = pc110pad_open; - pc110pad_dev->close = pc110pad_close; - - err = input_register_device(pc110pad_dev); - if (err) - goto err_free_dev; - - return 0; - - err_free_dev: - input_free_device(pc110pad_dev); - err_free_irq: - free_irq(pc110pad_irq, NULL); - err_release_region: - release_region(pc110pad_io, 4); - - return err; -} - -static void __exit pc110pad_exit(void) -{ - outb(PC110PAD_OFF, pc110pad_io + 2); - free_irq(pc110pad_irq, NULL); - input_unregister_device(pc110pad_dev); - release_region(pc110pad_io, 4); -} - -module_init(pc110pad_init); -module_exit(pc110pad_exit); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a2c9f7144864..6ab5f1d96eae 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -26,7 +26,6 @@ #include "synaptics.h" #include "logips2pp.h" #include "alps.h" -#include "hgpk.h" #include "lifebook.h" #include "trackpoint.h" #include "touchkit_ps2.h" @@ -114,8 +113,6 @@ ATTRIBUTE_GROUPS(psmouse_dev); */ static DEFINE_MUTEX(psmouse_mutex); -static struct workqueue_struct *kpsmoused_wq; - struct psmouse *psmouse_from_serio(struct serio *serio) { struct ps2dev *ps2dev = serio_get_drvdata(serio); @@ -241,12 +238,6 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } -void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, - unsigned long delay) -{ - queue_delayed_work(kpsmoused_wq, work, delay); -} - /* * __psmouse_set_state() sets new psmouse state and resets all flags. */ @@ -380,7 +371,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data) psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - psmouse_queue_work(psmouse, &psmouse->resync_work, 0); + schedule_work(&psmouse->resync_work); return; } @@ -393,9 +384,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data) return; } - if (psmouse->packet[1] == PSMOUSE_RET_ID || - (psmouse->protocol->type == PSMOUSE_HGPK && - psmouse->packet[1] == PSMOUSE_RET_BAT)) { + if (psmouse->packet[1] == PSMOUSE_RET_ID) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(ps2dev->serio); return; @@ -418,7 +407,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data) time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - psmouse_queue_work(psmouse, &psmouse->resync_work, 0); + schedule_work(&psmouse->resync_work); return; } @@ -837,14 +826,6 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = touchkit_ps2_detect, }, #endif -#ifdef CONFIG_MOUSE_PS2_OLPC - { - .type = PSMOUSE_HGPK, - .name = "OLPC HGPK", - .alias = "hgpk", - .detect = hgpk_detect, - }, -#endif #ifdef CONFIG_MOUSE_PS2_ELANTECH { .type = PSMOUSE_ELANTECH, @@ -1153,13 +1134,6 @@ static int psmouse_extensions(struct psmouse *psmouse, return PSMOUSE_ALPS; } - /* Try OLPC HGPK touchpad */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto, - set_properties, true)) { - return PSMOUSE_HGPK; - } - /* Try Elantech touchpad */ if (max_proto > PSMOUSE_IMEX && psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH, @@ -1331,7 +1305,7 @@ int psmouse_deactivate(struct psmouse *psmouse) static void psmouse_resync(struct work_struct *work) { struct psmouse *parent = NULL, *psmouse = - container_of(work, struct psmouse, resync_work.work); + container_of(work, struct psmouse, resync_work); struct serio *serio = psmouse->ps2dev.serio; psmouse_ret_t rc = PSMOUSE_GOOD_DATA; bool failed = false, enabled = false; @@ -1484,7 +1458,7 @@ static void psmouse_disconnect(struct serio *serio) /* make sure we don't have a resync in progress */ mutex_unlock(&psmouse_mutex); - flush_workqueue(kpsmoused_wq); + disable_work_sync(&psmouse->resync_work); mutex_lock(&psmouse_mutex); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { @@ -1591,16 +1565,16 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_deactivate(parent); } - psmouse = kzalloc(sizeof(*psmouse), GFP_KERNEL); + psmouse = kzalloc_obj(*psmouse); input_dev = input_allocate_device(); if (!psmouse || !input_dev) goto err_free; ps2_init(&psmouse->ps2dev, serio, psmouse_pre_receive_byte, psmouse_receive_byte); - INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync); + INIT_WORK(&psmouse->resync_work, psmouse_resync); psmouse->dev = input_dev; - snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); + scnprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); @@ -2035,27 +2009,17 @@ static int __init psmouse_init(void) lifebook_module_init(); synaptics_module_init(); - hgpk_module_init(); err = psmouse_smbus_module_init(); if (err) return err; - kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); - if (!kpsmoused_wq) { - pr_err("failed to create kpsmoused workqueue\n"); - err = -ENOMEM; - goto err_smbus_exit; - } - err = serio_register_driver(&psmouse_drv); if (err) - goto err_destroy_wq; + goto err_smbus_exit; return 0; -err_destroy_wq: - destroy_workqueue(kpsmoused_wq); err_smbus_exit: psmouse_smbus_module_exit(); return err; @@ -2064,7 +2028,6 @@ err_smbus_exit: static void __exit psmouse_exit(void) { serio_unregister_driver(&psmouse_drv); - destroy_workqueue(kpsmoused_wq); psmouse_smbus_module_exit(); } diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c index 93420f07b7d0..7fb4cbb2aca2 100644 --- a/drivers/input/mouse/psmouse-smbus.c +++ b/drivers/input/mouse/psmouse-smbus.c @@ -154,7 +154,7 @@ static void psmouse_smbus_schedule_remove(struct i2c_client *client) { struct psmouse_smbus_removal_work *rwork; - rwork = kzalloc(sizeof(*rwork), GFP_KERNEL); + rwork = kzalloc_obj(*rwork); if (rwork) { INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device); rwork->client = client; @@ -299,7 +299,7 @@ int __init psmouse_smbus_module_init(void) { int error; - psmouse_smbus_wq = alloc_workqueue("psmouse-smbus", 0, 0); + psmouse_smbus_wq = alloc_workqueue("psmouse-smbus", WQ_UNBOUND, 0); if (!psmouse_smbus_wq) return -ENOMEM; diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 4d8acfe0d82a..90ed8cd15d85 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -59,7 +59,7 @@ enum psmouse_type { PSMOUSE_TRACKPOINT, PSMOUSE_TOUCHKIT_PS2, PSMOUSE_CORTRON, - PSMOUSE_HGPK, + PSMOUSE_HGPK, /* No longer used */ PSMOUSE_ELANTECH, PSMOUSE_FSP, PSMOUSE_SYNAPTICS_RELATIVE, @@ -90,7 +90,7 @@ struct psmouse { void *private; struct input_dev *dev; struct ps2dev ps2dev; - struct delayed_work resync_work; + struct work_struct resync_work; const char *vendor; const char *name; const struct psmouse_protocol *protocol; @@ -132,8 +132,6 @@ struct psmouse { struct psmouse *psmouse_from_serio(struct serio *serio); -void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, - unsigned long delay); int psmouse_reset(struct psmouse *psmouse); void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index 44b136fc29aa..cda6febe3faf 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -1028,7 +1028,7 @@ int fsp_init(struct psmouse *psmouse) "Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n", ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver); - psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL); + psmouse->private = priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 218c8432a13b..c334a488700f 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -231,7 +231,7 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv) unsigned char c = serio->id.extra; int err = -ENOMEM; - sermouse = kzalloc(sizeof(*sermouse), GFP_KERNEL); + sermouse = kzalloc_obj(*sermouse); input_dev = input_allocate_device(); if (!sermouse || !input_dev) goto fail1; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index aba57abe6978..c70502e24031 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -161,8 +161,10 @@ static const char * const topbuttonpad_pnp_ids[] = { NULL }; +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS static const char * const smbus_pnp_ids[] = { /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ + "DLL060d", /* Dell Precision M3800 */ "LEN0048", /* X1 Carbon 3 */ "LEN0046", /* X250 */ "LEN0049", /* Yoga 11e */ @@ -188,14 +190,20 @@ static const char * const smbus_pnp_ids[] = { "LEN2044", /* L470 */ "LEN2054", /* E480 */ "LEN2055", /* E580 */ + "LEN2058", /* E490 */ "LEN2068", /* T14 Gen 1 */ + "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */ + "SYN3003", /* HP EliteBook 850 G1 */ "SYN3015", /* HP EliteBook 840 G2 */ "SYN3052", /* HP EliteBook 840 G4 */ "SYN3221", /* HP 15-ay000 */ "SYN323d", /* HP Spectre X360 13-w013dx */ "SYN3257", /* HP Envy 13-ad105ng */ + "TOS01f6", /* Dynabook Portege X30L-G */ + "TOS0213", /* Dynabook Portege X30-D */ NULL }; +#endif static const char * const forcepad_pnp_ids[] = { "SYN300D", @@ -734,7 +742,7 @@ static void synaptics_pt_create(struct psmouse *psmouse) { struct serio *serio; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) { psmouse_err(psmouse, "not enough memory for pass-through port\n"); @@ -1590,7 +1598,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse, synaptics_apply_quirks(psmouse, info); - psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL); + psmouse->private = priv = kzalloc_obj(*priv); if (!priv) return -ENOMEM; diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index a0d707e47d93..6f3d5c33b807 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -240,52 +240,57 @@ static inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate) */ static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg) { - int ret; + int error; - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_read_byte_data(client, reg & 0xff); + error = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (error) + return error; - return ret; + return i2c_smbus_read_byte_data(client, reg & 0xff); } static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val) { - int ret; + int error; - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_write_byte_data(client, reg & 0xff, val); + error = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (error) + return error; - return ret; + error = i2c_smbus_write_byte_data(client, reg & 0xff, val); + if (error) + return error; + + return error; } static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg) { - int ret; + int error; - ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); - if (ret == 0) - ret = i2c_smbus_read_word_data(client, reg & 0xff); + error = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (error) + return error; - return ret; + return i2c_smbus_read_word_data(client, reg & 0xff); } static int synaptics_i2c_config(struct i2c_client *client) { - int ret, control; + int control; + int error; u8 int_en; /* set Report Rate to Device Highest (>=80) and Sleep to normal */ - ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1); - if (ret) - return ret; + error = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1); + if (error) + return error; /* set Interrupt Disable to Func20 / Enable to Func10) */ int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK; - ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en); - if (ret) - return ret; + error = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en); + if (error) + return error; control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG); /* No Deceleration */ @@ -294,42 +299,49 @@ static int synaptics_i2c_config(struct i2c_client *client) control |= reduce_report ? 1 << REDUCE_REPORTING : 0; /* No Filter */ control |= no_filter ? 1 << NO_FILTER : 0; - ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control); - if (ret) - return ret; + error = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control); + if (error) + return error; return 0; } static int synaptics_i2c_reset_config(struct i2c_client *client) { - int ret; + int error; /* Reset the Touchpad */ - ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND); - if (ret) { + error = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND); + if (error) { dev_err(&client->dev, "Unable to reset device\n"); - } else { - usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100); - ret = synaptics_i2c_config(client); - if (ret) - dev_err(&client->dev, "Unable to config device\n"); + return error; + } + + usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100); + error = synaptics_i2c_config(client); + if (error) { + dev_err(&client->dev, "Unable to config device\n"); + return error; } - return ret; + return 0; } static int synaptics_i2c_check_error(struct i2c_client *client) { - int status, ret = 0; + int status; + int error; status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) & (CONFIGURED_MSK | ERROR_MSK); - if (status != CONFIGURED_MSK) - ret = synaptics_i2c_reset_config(client); + if (status != CONFIGURED_MSK) { + error = synaptics_i2c_reset_config(client); + if (error) + return error; + } - return ret; + return 0; } static bool synaptics_i2c_get_input(struct synaptics_i2c *touch) @@ -372,7 +384,7 @@ static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id) { struct synaptics_i2c *touch = dev_id; - mod_delayed_work(system_wq, &touch->dwork, 0); + mod_delayed_work(system_dfl_wq, &touch->dwork, 0); return IRQ_HANDLED; } @@ -421,10 +433,10 @@ static unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, delay = NO_DATA_SLEEP_MSECS; } return msecs_to_jiffies(delay); - } else { - delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS); - return round_jiffies_relative(delay); } + + delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS); + return round_jiffies_relative(delay); } /* Work Handler */ @@ -448,21 +460,21 @@ static void synaptics_i2c_work_handler(struct work_struct *work) * We poll the device once in THREAD_IRQ_SLEEP_SECS and * if error is detected, we try to reset and reconfigure the touchpad. */ - mod_delayed_work(system_wq, &touch->dwork, delay); + mod_delayed_work(system_dfl_wq, &touch->dwork, delay); } static int synaptics_i2c_open(struct input_dev *input) { struct synaptics_i2c *touch = input_get_drvdata(input); - int ret; + int error; - ret = synaptics_i2c_reset_config(touch->client); - if (ret) - return ret; + error = synaptics_i2c_reset_config(touch->client); + if (error) + return error; if (polling_req) - mod_delayed_work(system_wq, &touch->dwork, - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + mod_delayed_work(system_dfl_wq, &touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); return 0; } @@ -489,28 +501,27 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) input->id.bustype = BUS_I2C; input->id.version = synaptics_i2c_word_get(touch->client, INFO_QUERY_REG0); - input->dev.parent = &touch->client->dev; input->open = synaptics_i2c_open; input->close = synaptics_i2c_close; input_set_drvdata(input, touch); /* Register the device as mouse */ - __set_bit(EV_REL, input->evbit); - __set_bit(REL_X, input->relbit); - __set_bit(REL_Y, input->relbit); + input_set_capability(input, EV_REL, REL_X); + input_set_capability(input, EV_REL, REL_Y); /* Register device's buttons and keys */ - __set_bit(EV_KEY, input->evbit); - __set_bit(BTN_LEFT, input->keybit); + input_set_capability(input, EV_KEY, BTN_LEFT); } -static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) +static int synaptics_i2c_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct synaptics_i2c *touch; + int error; - touch = kzalloc(sizeof(*touch), GFP_KERNEL); + touch = devm_kzalloc(dev, sizeof(*touch), GFP_KERNEL); if (!touch) - return NULL; + return -ENOMEM; touch->client = client; touch->no_decel_param = no_decel; @@ -518,83 +529,46 @@ static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *clien set_scan_rate(touch, scan_rate); INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler); - return touch; -} - -static int synaptics_i2c_probe(struct i2c_client *client) -{ - int ret; - struct synaptics_i2c *touch; + error = synaptics_i2c_reset_config(client); + if (error) + return error; - touch = synaptics_i2c_touch_create(client); - if (!touch) - return -ENOMEM; - - ret = synaptics_i2c_reset_config(client); - if (ret) - goto err_mem_free; - - if (client->irq < 1) + if (client->irq <= 0) polling_req = true; - touch->input = input_allocate_device(); - if (!touch->input) { - ret = -ENOMEM; - goto err_mem_free; - } + touch->input = devm_input_allocate_device(dev); + if (!touch->input) + return -ENOMEM; synaptics_i2c_set_input_params(touch); if (!polling_req) { - dev_dbg(&touch->client->dev, - "Requesting IRQ: %d\n", touch->client->irq); - - ret = request_irq(touch->client->irq, synaptics_i2c_irq, - IRQ_TYPE_EDGE_FALLING, - DRIVER_NAME, touch); - if (ret) { - dev_warn(&touch->client->dev, - "IRQ request failed: %d, " - "falling back to polling\n", ret); + dev_dbg(dev, "Requesting IRQ: %d\n", client->irq); + + error = devm_request_irq(dev, client->irq, synaptics_i2c_irq, + IRQ_TYPE_EDGE_FALLING, + DRIVER_NAME, touch); + if (error) { + dev_warn(dev, "IRQ request failed: %d, falling back to polling\n", + error); polling_req = true; - synaptics_i2c_reg_set(touch->client, - INTERRUPT_EN_REG, 0); + synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, 0); } } if (polling_req) - dev_dbg(&touch->client->dev, - "Using polling at rate: %d times/sec\n", scan_rate); + dev_dbg(dev, "Using polling at rate: %d times/sec\n", scan_rate); /* Register the device in input subsystem */ - ret = input_register_device(touch->input); - if (ret) { - dev_err(&client->dev, - "Input device register failed: %d\n", ret); - goto err_input_free; + error = input_register_device(touch->input); + if (error) { + dev_err(dev, "Input device register failed: %d\n", error); + return error; } i2c_set_clientdata(client, touch); return 0; - -err_input_free: - input_free_device(touch->input); -err_mem_free: - kfree(touch); - - return ret; -} - -static void synaptics_i2c_remove(struct i2c_client *client) -{ - struct synaptics_i2c *touch = i2c_get_clientdata(client); - - if (!polling_req) - free_irq(client->irq, touch); - - input_unregister_device(touch->input); - kfree(touch); } static int synaptics_i2c_suspend(struct device *dev) @@ -612,16 +586,19 @@ static int synaptics_i2c_suspend(struct device *dev) static int synaptics_i2c_resume(struct device *dev) { - int ret; struct i2c_client *client = to_i2c_client(dev); struct synaptics_i2c *touch = i2c_get_clientdata(client); + struct input_dev *input = touch->input; + int error; - ret = synaptics_i2c_reset_config(client); - if (ret) - return ret; + error = synaptics_i2c_reset_config(client); + if (error) + return error; - mod_delayed_work(system_wq, &touch->dwork, - msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + guard(mutex)(&input->mutex); + if (input_device_enabled(input)) + mod_delayed_work(system_dfl_wq, &touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); return 0; } @@ -651,8 +628,6 @@ static struct i2c_driver synaptics_i2c_driver = { }, .probe = synaptics_i2c_probe, - .remove = synaptics_i2c_remove, - .id_table = synaptics_i2c_id_table, }; diff --git a/drivers/input/mouse/synaptics_usb.c b/drivers/input/mouse/synaptics_usb.c index 75e45f3ae675..880a0c79148c 100644 --- a/drivers/input/mouse/synaptics_usb.c +++ b/drivers/input/mouse/synaptics_usb.c @@ -220,25 +220,6 @@ resubmit: __func__, error); } -static struct usb_endpoint_descriptor * -synusb_get_in_endpoint(struct usb_host_interface *iface) -{ - - struct usb_endpoint_descriptor *endpoint; - int i; - - for (i = 0; i < iface->desc.bNumEndpoints; ++i) { - endpoint = &iface->endpoint[i].desc; - - if (usb_endpoint_is_int_in(endpoint)) { - /* we found our interrupt in endpoint */ - return endpoint; - } - } - - return NULL; -} - static int synusb_open(struct input_dev *dev) { struct synusb *synusb = input_get_drvdata(dev); @@ -307,11 +288,11 @@ static int synusb_probe(struct usb_interface *intf, return error; } - ep = synusb_get_in_endpoint(intf->cur_altsetting); - if (!ep) + error = usb_find_int_in_endpoint(intf->cur_altsetting, &ep); + if (error) return -ENODEV; - synusb = kzalloc(sizeof(*synusb), GFP_KERNEL); + synusb = kzalloc_obj(*synusb); input_dev = input_allocate_device(); if (!synusb || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 5f6643b69a2c..3bd8fdf56cd3 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -5,6 +5,7 @@ * Trademarks are the property of their respective owners. */ +#include <linux/array_size.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/serio.h> @@ -12,6 +13,7 @@ #include <linux/input.h> #include <linux/libps2.h> #include <linux/proc_fs.h> +#include <linux/string.h> #include <linux/uaccess.h> #include "psmouse.h" #include "trackpoint.h" @@ -393,6 +395,44 @@ static int trackpoint_reconnect(struct psmouse *psmouse) return 0; } +/* List of known incapable device PNP IDs */ +static const char * const dt_incompatible_devices[] = { + "LEN0304", + "LEN0306", + "LEN0317", + "LEN031A", + "LEN031B", + "LEN031C", + "LEN031D", +}; + +/* + * Checks if it's a doubletap capable device. + * The PNP ID format is "PNP: LEN030d PNP0f13". + */ +static bool trackpoint_is_dt_capable(const char *pnp_id) +{ + size_t i; + + if (!pnp_id) + return false; + + /* Must start with "PNP: LEN03" */ + if (!strstarts(pnp_id, "PNP: LEN03")) + return false; + + /* Ensure enough length before comparing */ + if (strlen(pnp_id) < 12) + return false; + + /* Check deny-list */ + for (i = 0; i < ARRAY_SIZE(dt_incompatible_devices); i++) { + if (!strncmp(pnp_id + 5, dt_incompatible_devices[i], 7)) + return false; + } + return true; +} + int trackpoint_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; @@ -409,7 +449,7 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) if (!set_properties) return 0; - tp = kzalloc(sizeof(*tp), GFP_KERNEL); + tp = kzalloc_obj(*tp); if (!tp) return -ENOMEM; @@ -470,6 +510,12 @@ int trackpoint_detect(struct psmouse *psmouse, bool set_properties) psmouse->vendor, firmware_id, (button_info & 0xf0) >> 4, button_info & 0x0f); + if (trackpoint_is_dt_capable(ps2dev->serio->firmware_id)) { + error = trackpoint_write(ps2dev, TP_DOUBLETAP, TP_DOUBLETAP_ENABLE); + if (error) + psmouse_warn(psmouse, "Failed to enable doubletap: %d\n", error); + } + return 0; } diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h index eb5412904fe0..3e03cdb39449 100644 --- a/drivers/input/mouse/trackpoint.h +++ b/drivers/input/mouse/trackpoint.h @@ -69,6 +69,8 @@ /* (how hard it is to drag */ /* with Z-axis pressed) */ +#define TP_DOUBLETAP 0x58 /* TrackPoint doubletap register */ + #define TP_MINDRAG 0x59 /* Minimum amount of force needed */ /* to trigger dragging */ @@ -110,6 +112,9 @@ external device will be forced to 1 */ #define TP_MASK_EXT_TAG 0x04 +/* Doubletap register values */ +#define TP_DOUBLETAP_ENABLE 0xFF /* Enable value */ +#define TP_DOUBLETAP_DISABLE 0xFE /* Disable value */ /* Power on Self Test Results */ #define TP_POR_SUCCESS 0x3B diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c index fb1d986a6895..aaecdd3d50b6 100644 --- a/drivers/input/mouse/vmmouse.c +++ b/drivers/input/mouse/vmmouse.c @@ -409,7 +409,7 @@ int vmmouse_init(struct psmouse *psmouse) if (error) return error; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); abs_dev = input_allocate_device(); if (!priv || !abs_dev) { error = -ENOMEM; diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 707cd28f4ba6..042a17fe81db 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -456,7 +456,7 @@ static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err = -ENOMEM; - mouse = kzalloc(sizeof(*mouse), GFP_KERNEL); + mouse = kzalloc_obj(*mouse); input_dev = input_allocate_device(); if (!mouse || !input_dev) goto fail1; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 505c562a5daa..d5c9b0a09fcf 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -543,7 +543,7 @@ static int mousedev_open(struct inode *inode, struct file *file) #endif mousedev = container_of(inode->i_cdev, struct mousedev, cdev); - client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); + client = kzalloc_obj(struct mousedev_client); if (!client) return -ENOMEM; @@ -853,7 +853,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, goto err_out; } - mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); + mousedev = kzalloc_obj(struct mousedev); if (!mousedev) { error = -ENOMEM; goto err_free_minor; diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index c0163b983ce6..5db58fc9e11b 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -82,6 +82,21 @@ config RMI4_F12 touchpads. For sensors that support relative pointing, F12 also provides mouse input. +config RMI4_F1A + bool "RMI4 Function 1A (0D pointing)" + help + Say Y here if you want to add support for RMI4 function 1A. + + Function 1A provides capacitive keys support for RMI4 devices. + +config RMI4_F21 + bool "RMI4 Function 21 (PRESSURE)" + help + Say Y here if you want to add support for RMI4 function 21. + + Function 21 provides buttons/pressure handling for RMI4 devices. + This includes support for buttons/pressure on PressurePad. + config RMI4_F30 bool "RMI4 Function 30 (GPIO LED)" help diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index 02f14c846861..35ae29f72497 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -8,6 +8,8 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o +rmi_core-$(CONFIG_RMI4_F1A) += rmi_f1a.o +rmi_core-$(CONFIG_RMI4_F21) += rmi_f21.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 diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c index b7fe6eb35a4e..ea3eb87a89af 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.c +++ b/drivers/input/rmi4/rmi_2d_sensor.c @@ -4,6 +4,7 @@ * Copyright (c) 2011 Unixphere */ +#include <linux/export.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/of.h> diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h index 7d335d809710..61a99c8a7a26 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.h +++ b/drivers/input/rmi4/rmi_2d_sensor.h @@ -7,6 +7,9 @@ #ifndef _RMI_2D_SENSOR_H #define _RMI_2D_SENSOR_H +#include <linux/rmi.h> +#include <linux/types.h> + enum rmi_2d_sensor_object_type { RMI_2D_OBJECT_NONE, RMI_2D_OBJECT_FINGER, diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 3aee04837205..687cb987bc13 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -4,6 +4,7 @@ * Copyright (c) 2011 Unixphere */ +#include <linux/export.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/irq.h> @@ -77,7 +78,7 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport) struct rmi_device *rmi_dev; int error; - rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL); + rmi_dev = kzalloc_obj(struct rmi_device); if (!rmi_dev) return -ENOMEM; @@ -360,6 +361,12 @@ static struct rmi_function_handler *fn_handlers[] = { #ifdef CONFIG_RMI4_F12 &rmi_f12_handler, #endif +#ifdef CONFIG_RMI4_F1A + &rmi_f1a_handler, +#endif +#ifdef CONFIG_RMI4_F21 + &rmi_f21_handler, +#endif #ifdef CONFIG_RMI4_F30 &rmi_f30_handler, #endif diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 2168b6cd7167..ccd9338a44db 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -21,6 +21,7 @@ #include <linux/irqdomain.h> #include <uapi/linux/input.h> #include <linux/rmi.h> +#include <linux/export.h> #include "rmi_bus.h" #include "rmi_driver.h" diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 3bfe9013043e..e84495caab15 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -133,6 +133,8 @@ extern struct rmi_function_handler rmi_f01_handler; extern struct rmi_function_handler rmi_f03_handler; extern struct rmi_function_handler rmi_f11_handler; extern struct rmi_function_handler rmi_f12_handler; +extern struct rmi_function_handler rmi_f1a_handler; +extern struct rmi_function_handler rmi_f21_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; diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index e1157ff0f00a..04f0e5578861 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -171,7 +171,7 @@ static int rmi_f03_register_pt(struct f03_data *f03) { struct serio *serio; - serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + serio = kzalloc_obj(struct serio); if (!serio) return -ENOMEM; diff --git a/drivers/input/rmi4/rmi_f1a.c b/drivers/input/rmi4/rmi_f1a.c new file mode 100644 index 000000000000..765e9eae4cdc --- /dev/null +++ b/drivers/input/rmi4/rmi_f1a.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2025 André Apitzsch <git@apitzsch.eu> + */ + +#include <linux/input.h> +#include <linux/property.h> +#include "rmi_driver.h" + +struct f1a_data { + struct input_dev *input; + + u32 *keymap; + unsigned int num_keys; +}; + +static int rmi_f1a_parse_device_properties(struct rmi_function *fn, struct f1a_data *f1a) +{ + static const char buttons_property[] = "linux,keycodes"; + struct device *dev = &fn->dev; + u32 *buttonmap; + int n_keys; + int error; + + if (!device_property_present(dev, buttons_property)) + return 0; + + n_keys = device_property_count_u32(dev, buttons_property); + if (n_keys <= 0) { + error = n_keys < 0 ? n_keys : -EINVAL; + dev_err(dev, "Invalid/malformed '%s' property: %d\n", + buttons_property, error); + return error; + } + + buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap), + GFP_KERNEL); + if (!buttonmap) + return -ENOMEM; + + error = device_property_read_u32_array(dev, buttons_property, + buttonmap, n_keys); + if (error) { + dev_err(dev, "Failed to parse '%s' property: %d\n", + buttons_property, error); + return error; + } + + f1a->keymap = buttonmap; + f1a->num_keys = n_keys; + + return 0; +} + +static irqreturn_t rmi_f1a_attention(int irq, void *ctx) +{ + struct rmi_function *fn = ctx; + struct f1a_data *f1a = dev_get_drvdata(&fn->dev); + char button_bitmask; + int key; + int error; + + error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, + &button_bitmask, sizeof(button_bitmask)); + if (error) { + dev_err(&fn->dev, "Failed to read object data. Code: %d.\n", + error); + return IRQ_RETVAL(error); + } + + for (key = 0; key < f1a->num_keys; key++) + input_report_key(f1a->input, f1a->keymap[key], + button_bitmask & BIT(key)); + + return IRQ_HANDLED; +} + +static int rmi_f1a_config(struct rmi_function *fn) +{ + struct f1a_data *f1a = dev_get_drvdata(&fn->dev); + struct rmi_driver *drv = fn->rmi_dev->driver; + + if (f1a->num_keys) + drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); + + return 0; +} + +static int rmi_f1a_initialize(struct rmi_function *fn, struct f1a_data *f1a) +{ + int error; + int i; + + error = rmi_f1a_parse_device_properties(fn, f1a); + if (error) + return error; + + for (i = 0; i < f1a->num_keys; i++) + input_set_capability(f1a->input, EV_KEY, f1a->keymap[i]); + + f1a->input->keycode = f1a->keymap; + f1a->input->keycodemax = f1a->num_keys; + f1a->input->keycodesize = sizeof(f1a->keymap[0]); + + return 0; +} + +static int rmi_f1a_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 f1a_data *f1a; + int error; + + if (!drv_data->input) { + dev_info(&fn->dev, "F1A: no input device found, ignoring\n"); + return -ENXIO; + } + + f1a = devm_kzalloc(&fn->dev, sizeof(*f1a), GFP_KERNEL); + if (!f1a) + return -ENOMEM; + + f1a->input = drv_data->input; + + error = rmi_f1a_initialize(fn, f1a); + if (error) + return error; + + dev_set_drvdata(&fn->dev, f1a); + + return 0; +} + +struct rmi_function_handler rmi_f1a_handler = { + .driver = { + .name = "rmi4_f1a", + }, + .func = 0x1a, + .probe = rmi_f1a_probe, + .config = rmi_f1a_config, + .attention = rmi_f1a_attention, +}; diff --git a/drivers/input/rmi4/rmi_f21.c b/drivers/input/rmi4/rmi_f21.c new file mode 100644 index 000000000000..e3a9dfc3f0ec --- /dev/null +++ b/drivers/input/rmi4/rmi_f21.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2025 Synaptics Incorporated + */ + +#include <linux/bits.h> +#include <linux/dev_printk.h> +#include <linux/kernel.h> +#include <linux/rmi.h> +#include <linux/input.h> +#include <linux/slab.h> +#include "rmi_driver.h" + +#define RMI_F21_SENSOR_COUNT_MASK GENMASK(3, 0) +#define RMI_F21_FINGER_COUNT_PRESENT BIT(5) +#define RMI_F21_NEW_REPORT_FORMAT BIT(6) + +#define RMI_F21_FINGER_COUNT_MASK GENMASK(3, 0) + +#define RMI_F21_MAX_SENSORS 16 +#define RMI_F21_MAX_FINGERS 16 +#define RMI_F21_DATA_REGS_MAX_SIZE (RMI_F21_MAX_SENSORS * 2 + \ + RMI_F21_MAX_FINGERS * 2 + 1) + +#define RMI_F21_FORCE_CLICK_BIT BIT(0) + +#define RMI_F21_FORCEPAD_BUTTON_COUNT 1 + +struct f21_data { + struct input_dev *input; + u16 key_code; + + unsigned int attn_data_size; + unsigned int attn_data_button_offset; + + unsigned int data_reg_size; + unsigned int data_reg_button_offset; + u8 data_regs[RMI_F21_DATA_REGS_MAX_SIZE]; +}; + +static irqreturn_t rmi_f21_attention(int irq, void *ctx) +{ + struct rmi_function *fn = ctx; + struct f21_data *f21 = dev_get_drvdata(&fn->dev); + struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); + u8 *pdata; + int error; + bool pressed; + + if (drvdata->attn_data.data) { + if (drvdata->attn_data.size < f21->attn_data_size) { + dev_warn(&fn->dev, "f21 interrupt, but data is missing\n"); + return IRQ_HANDLED; + } + + pdata = drvdata->attn_data.data + f21->attn_data_button_offset; + + drvdata->attn_data.data += f21->attn_data_size; + drvdata->attn_data.size -= f21->attn_data_size; + } else { + error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr, + f21->data_regs, f21->data_reg_size); + if (error) { + dev_err(&fn->dev, "failed to read f21 data registers: %d\n", + error); + return IRQ_RETVAL(error); + } + + pdata = f21->data_regs + f21->data_reg_button_offset; + } + + pressed = *pdata & RMI_F21_FORCE_CLICK_BIT; + input_report_key(f21->input, f21->key_code, pressed); + + return IRQ_HANDLED; +} + +static int rmi_f21_config(struct rmi_function *fn) +{ + struct rmi_driver *drv = fn->rmi_dev->driver; + + drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); + + return 0; +} + +static int rmi_f21_initialize(struct rmi_function *fn, struct f21_data *f21) +{ + struct input_dev *input = f21->input; + + f21->key_code = BTN_LEFT; + + input->keycode = &f21->key_code; + input->keycodesize = sizeof(f21->key_code); + input->keycodemax = RMI_F21_FORCEPAD_BUTTON_COUNT; + + input_set_capability(input, EV_KEY, f21->key_code); + __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); + + return 0; +} + +static int rmi_f21_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 f21_data *f21; + unsigned int sensor_count; + unsigned int max_fingers; + unsigned int query15_offset; + u8 query15_data; + int error; + + if (!drv_data->input) { + dev_info(&fn->dev, "f21: no input device found, ignoring\n"); + return -ENXIO; + } + + f21 = devm_kzalloc(&fn->dev, sizeof(*f21), GFP_KERNEL); + if (!f21) + return -ENOMEM; + + f21->input = drv_data->input; + + error = rmi_f21_initialize(fn, f21); + if (error) + return error; + + dev_set_drvdata(&fn->dev, f21); + + sensor_count = fn->fd.query_base_addr & RMI_F21_SENSOR_COUNT_MASK; + if (fn->fd.query_base_addr & RMI_F21_FINGER_COUNT_PRESENT) { + query15_offset = fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT ? 2 : 1; + error = rmi_read_block(fn->rmi_dev, + fn->fd.query_base_addr + query15_offset, + &query15_data, sizeof(query15_data)); + if (error) + return dev_err_probe(&fn->dev, error, + "failed to read 'query15' data"); + + max_fingers = query15_data & RMI_F21_FINGER_COUNT_MASK; + } else { + max_fingers = 5; + } + + if (fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT) { + /* Each finger uses one byte, and the button state uses one byte.*/ + f21->attn_data_size = max_fingers + 1; + f21->attn_data_button_offset = f21->attn_data_size - 1; + /* + * Each sensor uses two bytes, the button state uses one byte, + * and each finger uses two bytes. + */ + f21->data_reg_size = sensor_count * 2 + 1 + max_fingers * 2; + f21->data_reg_button_offset = sensor_count * 2; + } else { + /* + * Regardless of the transport each finger uses two bytes, + * and the button state uses one byte. + */ + f21->attn_data_size = sensor_count * 2 + 1; + f21->attn_data_button_offset = sensor_count * 2; + + f21->data_reg_size = f21->attn_data_size; + f21->data_reg_button_offset = f21->attn_data_button_offset; + } + + return 0; +} + +struct rmi_function_handler rmi_f21_handler = { + .driver = { + .name = "rmi4_f21", + }, + .func = 0x21, + .probe = rmi_f21_probe, + .config = rmi_f21_config, + .attention = rmi_f21_attention, +}; diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index d760af4cc12e..f1947f03b06a 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -4,6 +4,7 @@ * Copyright (C) 2016 Zodiac Inflight Innovations */ +#include "linux/device.h" #include <linux/kernel.h> #include <linux/rmi.h> #include <linux/firmware.h> @@ -289,39 +290,30 @@ static int rmi_f34_update_firmware(struct f34_data *f34, return rmi_f34_flash_firmware(f34, syn_fw); } -static int rmi_f34_status(struct rmi_function *fn) -{ - struct f34_data *f34 = dev_get_drvdata(&fn->dev); - - /* - * The status is the percentage complete, or once complete, - * zero for success or a negative return code. - */ - return f34->update_status; -} - static ssize_t rmi_driver_bootloader_id_show(struct device *dev, struct device_attribute *dattr, char *buf) { struct rmi_driver_data *data = dev_get_drvdata(dev); - struct rmi_function *fn = data->f34_container; + struct rmi_function *fn; struct f34_data *f34; - if (fn) { - f34 = dev_get_drvdata(&fn->dev); - - if (f34->bl_version == 5) - return sysfs_emit(buf, "%c%c\n", - f34->bootloader_id[0], - f34->bootloader_id[1]); - else - return sysfs_emit(buf, "V%d.%d\n", - f34->bootloader_id[1], - f34->bootloader_id[0]); - } + fn = data->f34_container; + if (!fn) + return -ENODEV; - return 0; + f34 = dev_get_drvdata(&fn->dev); + if (!f34) + return -ENODEV; + + if (f34->bl_version == 5) + return sysfs_emit(buf, "%c%c\n", + f34->bootloader_id[0], + f34->bootloader_id[1]); + else + return sysfs_emit(buf, "V%d.%d\n", + f34->bootloader_id[1], + f34->bootloader_id[0]); } static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL); @@ -334,13 +326,16 @@ static ssize_t rmi_driver_configuration_id_show(struct device *dev, struct rmi_function *fn = data->f34_container; struct f34_data *f34; - if (fn) { - f34 = dev_get_drvdata(&fn->dev); + fn = data->f34_container; + if (!fn) + return -ENODEV; + + f34 = dev_get_drvdata(&fn->dev); + if (!f34) + return -ENODEV; - return sysfs_emit(buf, "%s\n", f34->configuration_id); - } - return 0; + return sysfs_emit(buf, "%s\n", f34->configuration_id); } static DEVICE_ATTR(configuration_id, 0444, @@ -356,10 +351,14 @@ static int rmi_firmware_update(struct rmi_driver_data *data, if (!data->f34_container) { dev_warn(dev, "%s: No F34 present!\n", __func__); - return -EINVAL; + return -ENODEV; } f34 = dev_get_drvdata(&data->f34_container->dev); + if (!f34) { + dev_warn(dev, "%s: No valid F34 present!\n", __func__); + return -ENODEV; + } if (f34->bl_version >= 7) { if (data->pdt_props & HAS_BSR) { @@ -485,10 +484,18 @@ static ssize_t rmi_driver_update_fw_status_show(struct device *dev, char *buf) { struct rmi_driver_data *data = dev_get_drvdata(dev); - int update_status = 0; + struct f34_data *f34; + int update_status = -ENODEV; - if (data->f34_container) - update_status = rmi_f34_status(data->f34_container); + /* + * The status is the percentage complete, or once complete, + * zero for success or a negative return code. + */ + if (data->f34_container) { + f34 = dev_get_drvdata(&data->f34_container->dev); + if (f34) + update_status = f34->update_status; + } return sysfs_emit(buf, "%d\n", update_status); } @@ -508,33 +515,21 @@ static const struct attribute_group rmi_firmware_attr_group = { .attrs = rmi_firmware_attrs, }; -static int rmi_f34_probe(struct rmi_function *fn) +static int rmi_f34v5_probe(struct f34_data *f34) { - struct f34_data *f34; - unsigned char f34_queries[9]; + struct rmi_function *fn = f34->fn; + u8 f34_queries[9]; bool has_config_id; - u8 version = fn->fd.function_version; - int ret; - - f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); - if (!f34) - return -ENOMEM; - - f34->fn = fn; - dev_set_drvdata(&fn->dev, f34); - - /* v5 code only supported version 0, try V7 probe */ - if (version > 0) - return rmi_f34v7_probe(f34); + int error; f34->bl_version = 5; - ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, - f34_queries, sizeof(f34_queries)); - if (ret) { + error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, + f34_queries, sizeof(f34_queries)); + if (error) { dev_err(&fn->dev, "%s: Failed to query properties\n", __func__); - return ret; + return error; } snprintf(f34->bootloader_id, sizeof(f34->bootloader_id), @@ -560,11 +555,11 @@ static int rmi_f34_probe(struct rmi_function *fn) f34->v5.config_blocks); if (has_config_id) { - ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr, - f34_queries, sizeof(f34_queries)); - if (ret) { + error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr, + f34_queries, sizeof(f34_queries)); + if (error) { dev_err(&fn->dev, "Failed to read F34 config ID\n"); - return ret; + return error; } snprintf(f34->configuration_id, sizeof(f34->configuration_id), @@ -573,12 +568,34 @@ static int rmi_f34_probe(struct rmi_function *fn) f34_queries[2], f34_queries[3]); rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n", - f34->configuration_id); + f34->configuration_id); } return 0; } +static int rmi_f34_probe(struct rmi_function *fn) +{ + struct f34_data *f34; + u8 version = fn->fd.function_version; + int error; + + f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); + if (!f34) + return -ENOMEM; + + f34->fn = fn; + + /* v5 code only supported version 0 */ + error = version == 0 ? rmi_f34v5_probe(f34) : rmi_f34v7_probe(f34); + if (error) + return error; + + dev_set_drvdata(&fn->dev, f34); + + return 0; +} + int rmi_f34_create_sysfs(struct rmi_device *rmi_dev) { return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group); diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 5c3da910b5b2..61909e1a39e2 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -372,8 +372,6 @@ static const struct vb2_ops rmi_f54_queue_ops = { .queue_setup = rmi_f54_queue_setup, .buf_queue = rmi_f54_buffer_queue, .stop_streaming = rmi_f54_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct vb2_queue rmi_f54_queue = { @@ -540,6 +538,8 @@ static void rmi_f54_work(struct work_struct *work) int error; int i; + mutex_lock(&f54->data_mutex); + report_size = rmi_f54_get_report_size(f54); if (report_size == 0) { dev_err(&fn->dev, "Bad report size, report type=%d\n", @@ -548,8 +548,6 @@ static void rmi_f54_work(struct work_struct *work) goto error; /* retry won't help */ } - mutex_lock(&f54->data_mutex); - /* * Need to check if command has completed. * If not try again later. diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index 17edc1597446..5f15a6462056 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -55,19 +55,6 @@ config SERIO_SERPORT To compile this driver as a module, choose M here: the module will be called serport. -config SERIO_CT82C710 - tristate "ct82c710 Aux port controller" - depends on X86 - help - Say Y here if you have a Texas Instruments TravelMate notebook - equipped with the ct82c710 chip and want to use a mouse connected - to the "QuickPort". - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ct82c710. - config SERIO_Q40KBD tristate "Q40 keyboard controller" depends on Q40 @@ -276,8 +263,8 @@ config SERIO_OLPC_APSP config HYPERV_KEYBOARD tristate "Microsoft Synthetic Keyboard driver" - depends on HYPERV - default HYPERV + depends on HYPERV_VMBUS + default HYPERV_VMBUS help Select this option to enable the Hyper-V Keyboard driver. diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index 6d97bad7b844..8ab98f4aa28d 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_SERIO) += serio.o obj-$(CONFIG_SERIO_I8042) += i8042.o obj-$(CONFIG_SERIO_PARKBD) += parkbd.o obj-$(CONFIG_SERIO_SERPORT) += serport.o -obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c index aa445b1941e9..4bf37db65b76 100644 --- a/drivers/input/serio/altera_ps2.c +++ b/drivers/input/serio/altera_ps2.c @@ -81,7 +81,7 @@ static int altera_ps2_probe(struct platform_device *pdev) struct serio *serio; int error, irq; - ps2if = devm_kzalloc(&pdev->dev, sizeof(struct ps2if), GFP_KERNEL); + ps2if = devm_kzalloc(&pdev->dev, sizeof(*ps2if), GFP_KERNEL); if (!ps2if) return -ENOMEM; @@ -100,7 +100,7 @@ static int altera_ps2_probe(struct platform_device *pdev) return error; } - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index de4b3915c37d..046b8f388eb6 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -114,8 +114,8 @@ static int amba_kmi_probe(struct amba_device *dev, if (ret) return ret; - kmi = kzalloc(sizeof(*kmi), GFP_KERNEL); - io = kzalloc(sizeof(*io), GFP_KERNEL); + kmi = kzalloc_obj(*kmi); + io = kzalloc_obj(*io); if (!kmi || !io) { ret = -ENOMEM; goto out; diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 81b3a053df81..e346bf53eb16 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -150,7 +150,7 @@ static int ams_delta_serio_init(struct platform_device *pdev) return err; } - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c index b815337be2f4..0aa4ab00af35 100644 --- a/drivers/input/serio/apbps2.c +++ b/drivers/input/serio/apbps2.c @@ -67,7 +67,7 @@ static irqreturn_t apbps2_isr(int irq, void *dev_id) rxflags = (status & APBPS2_STATUS_PE) ? SERIO_PARITY : 0; rxflags |= (status & APBPS2_STATUS_FE) ? SERIO_FRAME : 0; - /* clear error bits? */ + /* Clear error bits */ if (rxflags) iowrite32be(0, &priv->regs->status); @@ -82,9 +82,9 @@ static irqreturn_t apbps2_isr(int irq, void *dev_id) static int apbps2_write(struct serio *io, unsigned char val) { struct apbps2_priv *priv = io->port_data; - unsigned int tleft = 10000; /* timeout in 100ms */ + unsigned int tleft = 10000; /* Timeout in 100ms */ - /* delay until PS/2 controller has room for more chars */ + /* Delay until PS/2 controller has room for more chars */ while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_TF) && tleft--) udelay(10); @@ -104,7 +104,7 @@ static int apbps2_open(struct serio *io) struct apbps2_priv *priv = io->port_data; int limit; - /* clear error flags */ + /* Clear error flags */ iowrite32be(0, &priv->regs->status); /* Clear old data if available (unlikely) */ @@ -112,7 +112,7 @@ static int apbps2_open(struct serio *io) while ((ioread32be(&priv->regs->status) & APBPS2_STATUS_DR) && --limit) ioread32be(&priv->regs->data); - /* Enable reciever and it's interrupt */ + /* Enable receiver and its interrupt */ iowrite32be(APBPS2_CTRL_RE | APBPS2_CTRL_RI, &priv->regs->ctrl); return 0; @@ -122,7 +122,7 @@ static void apbps2_close(struct serio *io) { struct apbps2_priv *priv = io->port_data; - /* stop interrupts at PS/2 HW level */ + /* Stop interrupts at PS/2 HW level */ iowrite32be(0, &priv->regs->ctrl); } @@ -139,7 +139,7 @@ static int apbps2_of_probe(struct platform_device *ofdev) return -ENOMEM; } - /* Find Device Address */ + /* Find device address */ priv->regs = devm_platform_get_and_ioremap_resource(ofdev, 0, NULL); if (IS_ERR(priv->regs)) return PTR_ERR(priv->regs); @@ -165,7 +165,7 @@ static int apbps2_of_probe(struct platform_device *ofdev) /* Set reload register to core freq in kHz/10 */ iowrite32be(freq_hz / 10000, &priv->regs->reload); - priv->io = kzalloc(sizeof(*priv->io), GFP_KERNEL); + priv->io = kzalloc_obj(*priv->io); if (!priv->io) return -ENOMEM; diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c index e991c72296c9..2eb069a0f054 100644 --- a/drivers/input/serio/arc_ps2.c +++ b/drivers/input/serio/arc_ps2.c @@ -155,7 +155,7 @@ static int arc_ps2_create_port(struct platform_device *pdev, struct arc_ps2_port *port = &arc_ps2->port[index]; struct serio *io; - io = kzalloc(sizeof(*io), GFP_KERNEL); + io = kzalloc_obj(*io); if (!io) return -ENOMEM; @@ -189,8 +189,7 @@ static int arc_ps2_probe(struct platform_device *pdev) if (irq < 0) return -EINVAL; - arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(struct arc_ps2_data), - GFP_KERNEL); + arc_ps2 = devm_kzalloc(&pdev->dev, sizeof(*arc_ps2), GFP_KERNEL); if (!arc_ps2) { dev_err(&pdev->dev, "out of memory\n"); return -ENOMEM; diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c deleted file mode 100644 index 053a15988c45..000000000000 --- a/drivers/input/serio/ct82c710.c +++ /dev/null @@ -1,239 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - -/* - * 82C710 C&T mouse port chip driver for Linux - */ - -#include <linux/delay.h> -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/serio.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include <asm/io.h> - -MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); -MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); -MODULE_LICENSE("GPL"); - -/* - * ct82c710 interface - */ - -#define CT82C710_DEV_IDLE 0x01 /* Device Idle */ -#define CT82C710_RX_FULL 0x02 /* Device Char received */ -#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */ -#define CT82C710_RESET 0x08 /* Device Reset */ -#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */ -#define CT82C710_ERROR_FLAG 0x20 /* Device Error */ -#define CT82C710_CLEAR 0x40 /* Device Clear */ -#define CT82C710_ENABLE 0x80 /* Device Enable */ - -#define CT82C710_IRQ 12 - -#define CT82C710_DATA ct82c710_iores.start -#define CT82C710_STATUS (ct82c710_iores.start + 1) - -static struct serio *ct82c710_port; -static struct platform_device *ct82c710_device; -static struct resource ct82c710_iores; - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id) -{ - return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0); -} - -/* - * Wait for device to send output char and flush any input char. - */ - -static int ct82c170_wait(void) -{ - int timeout = 60000; - - while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) - != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { - - if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); - - udelay(1); - timeout--; - } - - return !timeout; -} - -static void ct82c710_close(struct serio *serio) -{ - if (ct82c170_wait()) - printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); - - outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); - - if (ct82c170_wait()) - printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); - - free_irq(CT82C710_IRQ, NULL); -} - -static int ct82c710_open(struct serio *serio) -{ - unsigned char status; - int err; - - err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL); - if (err) - return err; - - status = inb_p(CT82C710_STATUS); - - status |= (CT82C710_ENABLE | CT82C710_RESET); - outb_p(status, CT82C710_STATUS); - - status &= ~(CT82C710_RESET); - outb_p(status, CT82C710_STATUS); - - status |= CT82C710_INTS_ON; - outb_p(status, CT82C710_STATUS); /* Enable interrupts */ - - while (ct82c170_wait()) { - printk(KERN_ERR "ct82c710: Device busy in open()\n"); - status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); - outb_p(status, CT82C710_STATUS); - free_irq(CT82C710_IRQ, NULL); - return -EBUSY; - } - - return 0; -} - -/* - * Write to the 82C710 mouse device. - */ - -static int ct82c710_write(struct serio *port, unsigned char c) -{ - if (ct82c170_wait()) return -1; - outb_p(c, CT82C710_DATA); - return 0; -} - -/* - * See if we can find a 82C710 device. Read mouse address. - */ - -static int __init ct82c710_detect(void) -{ - outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ - outb_p(0xaa, 0x3fa); /* Inverse of 55 */ - outb_p(0x36, 0x3fa); /* Address the chip */ - outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ - outb_p(0x1b, 0x2fa); /* Inverse of e4 */ - outb_p(0x0f, 0x390); /* Write index */ - if (inb_p(0x391) != 0xe4) /* Config address found? */ - return -ENODEV; /* No: no 82C710 here */ - - outb_p(0x0d, 0x390); /* Write index */ - ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ - ct82c710_iores.end = ct82c710_iores.start + 1; - ct82c710_iores.flags = IORESOURCE_IO; - outb_p(0x0f, 0x390); - outb_p(0x0f, 0x391); /* Close config mode */ - - return 0; -} - -static int ct82c710_probe(struct platform_device *dev) -{ - ct82c710_port = kzalloc(sizeof(*ct82c710_port), GFP_KERNEL); - if (!ct82c710_port) - return -ENOMEM; - - ct82c710_port->id.type = SERIO_8042; - ct82c710_port->dev.parent = &dev->dev; - ct82c710_port->open = ct82c710_open; - ct82c710_port->close = ct82c710_close; - ct82c710_port->write = ct82c710_write; - strscpy(ct82c710_port->name, "C&T 82c710 mouse port", - sizeof(ct82c710_port->name)); - snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys), - "isa%16llx/serio0", (unsigned long long)CT82C710_DATA); - - serio_register_port(ct82c710_port); - - printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n", - (unsigned long long)CT82C710_DATA, CT82C710_IRQ); - - return 0; -} - -static void ct82c710_remove(struct platform_device *dev) -{ - serio_unregister_port(ct82c710_port); -} - -static struct platform_driver ct82c710_driver = { - .driver = { - .name = "ct82c710", - }, - .probe = ct82c710_probe, - .remove = ct82c710_remove, -}; - - -static int __init ct82c710_init(void) -{ - int error; - - error = ct82c710_detect(); - if (error) - return error; - - error = platform_driver_register(&ct82c710_driver); - if (error) - return error; - - ct82c710_device = platform_device_alloc("ct82c710", -1); - if (!ct82c710_device) { - error = -ENOMEM; - goto err_unregister_driver; - } - - error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1); - if (error) - goto err_free_device; - - error = platform_device_add(ct82c710_device); - if (error) - goto err_free_device; - - return 0; - - err_free_device: - platform_device_put(ct82c710_device); - err_unregister_driver: - platform_driver_unregister(&ct82c710_driver); - return error; -} - -static void __exit ct82c710_exit(void) -{ - platform_device_unregister(ct82c710_device); - platform_driver_unregister(&ct82c710_driver); -} - -module_init(ct82c710_init); -module_exit(ct82c710_exit); diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 4fada5bc2a38..22b2f57fd91f 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -251,6 +251,8 @@ static bool gscps2_report_data(struct gscps2port *ps2port) /** * gscps2_interrupt() - Interruption service routine + * @irq: interrupt number which triggered (unused) + * @dev: device pointer (unused) * * This function reads received PS/2 bytes and processes them on * all interfaces. @@ -329,6 +331,8 @@ static void gscps2_close(struct serio *port) /** * gscps2_probe() - Probes PS2 devices + * @dev: pointer to parisc_device struct which will be probed + * * @return: success/error report */ @@ -346,8 +350,8 @@ static int __init gscps2_probe(struct parisc_device *dev) if (dev->id.sversion == 0x96) hpa += GSC_DINO_OFFSET; - ps2port = kzalloc(sizeof(*ps2port), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + ps2port = kzalloc_obj(*ps2port); + serio = kzalloc_obj(*serio); if (!ps2port || !serio) { ret = -ENOMEM; goto fail_nomem; @@ -420,6 +424,8 @@ fail_nomem: /** * gscps2_remove() - Removes PS2 devices + * @dev: pointer to parisc_device which shall be removed + * * @return: success/error report */ diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c index d36e89d6fc54..2680a816c393 100644 --- a/drivers/input/serio/hil_mlc.c +++ b/drivers/input/serio/hil_mlc.c @@ -54,6 +54,7 @@ #include <linux/hil_mlc.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -938,7 +939,7 @@ int hil_mlc_register(hil_mlc *mlc) for (i = 0; i < HIL_MLC_DEVMEM; i++) { struct serio *mlc_serio; hil_mlc_copy_di_scratch(mlc, i); - mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL); + mlc_serio = kzalloc_obj(*mlc_serio); mlc->serio[i] = mlc_serio; if (!mlc->serio[i]) { for (; i >= 0; i--) @@ -1017,7 +1018,7 @@ static int __init hil_mlc_init(void) static void __exit hil_mlc_exit(void) { - del_timer_sync(&hil_mlcs_kicker); + timer_delete_sync(&hil_mlcs_kicker); tasklet_kill(&hil_mlcs_tasklet); } diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 13eacf6ab431..1461ef319f92 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -63,6 +63,7 @@ #include <linux/hp_sdc.h> #include <linux/errno.h> +#include <linux/export.h> #include <linux/init.h> #include <linux/module.h> #include <linux/ioport.h> @@ -980,7 +981,7 @@ static void hp_sdc_exit(void) free_irq(hp_sdc.irq, &hp_sdc); write_unlock_irq(&hp_sdc.lock); - del_timer_sync(&hp_sdc.kicker); + timer_delete_sync(&hp_sdc.kicker); tasklet_kill(&hp_sdc.task); diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c index 0ee7505427ac..13434b9330c8 100644 --- a/drivers/input/serio/hyperv-keyboard.c +++ b/drivers/input/serio/hyperv-keyboard.c @@ -316,8 +316,8 @@ static int hv_kbd_probe(struct hv_device *hv_dev, struct serio *hv_serio; int error; - kbd_dev = kzalloc(sizeof(*kbd_dev), GFP_KERNEL); - hv_serio = kzalloc(sizeof(*hv_serio), GFP_KERNEL); + kbd_dev = kzalloc_obj(*kbd_dev); + hv_serio = kzalloc_obj(*hv_serio); if (!kbd_dev || !hv_serio) { error = -ENOMEM; goto err_free_mem; diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 6ed9fc34948c..8ebdf4fb9030 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -116,6 +116,17 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_NEVER) }, { + /* + * ASUS Zenbook UX425QA_UM425QA + * Some Zenbooks report "Zenbook" with a lowercase b. + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Zenbook UX425QA_UM425QA"), + }, + .driver_data = (void *)(SERIO_QUIRK_PROBE_DEFER | SERIO_QUIRK_RESET_NEVER) + }, + { /* ASUS ZenBook UX425UA/QA */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), @@ -1155,6 +1166,41 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X5KK45xS_X5SP45xS"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, /* * A lot of modern Clevo barebones have touchpad and/or keyboard issues * after suspend fixable with the forcenorestore quirk. diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index cab5a4c5baf5..8bcce11cb7ce 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -10,6 +10,7 @@ #include <linux/types.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/ioport.h> @@ -1323,7 +1324,7 @@ static int i8042_create_kbd_port(void) struct serio *serio; struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO]; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; @@ -1353,7 +1354,7 @@ static int i8042_create_aux_port(int idx) int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx; struct i8042_port *port = &i8042_ports[port_no]; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c index d2c7ffb9a946..4ef60c24e788 100644 --- a/drivers/input/serio/ioc3kbd.c +++ b/drivers/input/serio/ioc3kbd.c @@ -139,11 +139,11 @@ static int ioc3kbd_probe(struct platform_device *pdev) if (!d) return -ENOMEM; - sk = kzalloc(sizeof(*sk), GFP_KERNEL); + sk = kzalloc_obj(*sk); if (!sk) return -ENOMEM; - sa = kzalloc(sizeof(*sa), GFP_KERNEL); + sa = kzalloc_obj(*sa); if (!sa) { kfree(sk); return -ENOMEM; diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index c22ea532276e..05b64277aecd 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -8,6 +8,7 @@ #include <linux/delay.h> +#include <linux/export.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/interrupt.h> @@ -153,10 +154,8 @@ EXPORT_SYMBOL(ps2_end_command); */ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) { - if (maxbytes > sizeof(ps2dev->cmdbuf)) { - WARN_ON(1); + if (WARN_ON(maxbytes > sizeof(ps2dev->cmdbuf))) maxbytes = sizeof(ps2dev->cmdbuf); - } ps2_begin_command(ps2dev); @@ -269,15 +268,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) int i; u8 send_param[16]; - if (receive > sizeof(ps2dev->cmdbuf)) { - WARN_ON(1); + if (WARN_ON(receive > sizeof(ps2dev->cmdbuf))) return -EINVAL; - } - if (send && !param) { - WARN_ON(1); + if (WARN_ON(send && !param)) return -EINVAL; - } memcpy(send_param, param, send); diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index 3d28a5cddd61..fb41e7f5af46 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -117,7 +117,7 @@ static struct serio *maceps2_allocate_port(int idx) { struct serio *serio; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (serio) { serio->id.type = SERIO_8042; serio->write = maceps2_write; diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c index a24324830021..ccc40634f582 100644 --- a/drivers/input/serio/olpc_apsp.c +++ b/drivers/input/serio/olpc_apsp.c @@ -171,7 +171,7 @@ static int olpc_apsp_probe(struct platform_device *pdev) struct olpc_apsp *priv; int error; - priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -188,7 +188,7 @@ static int olpc_apsp_probe(struct platform_device *pdev) return priv->irq; /* KEYBOARD */ - kb_serio = kzalloc(sizeof(*kb_serio), GFP_KERNEL); + kb_serio = kzalloc_obj(*kb_serio); if (!kb_serio) return -ENOMEM; kb_serio->id.type = SERIO_8042_XL; @@ -203,7 +203,7 @@ static int olpc_apsp_probe(struct platform_device *pdev) serio_register_port(kb_serio); /* TOUCHPAD */ - pad_serio = kzalloc(sizeof(*pad_serio), GFP_KERNEL); + pad_serio = kzalloc_obj(*pad_serio); if (!pad_serio) { error = -ENOMEM; goto err_pad; diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 22fe55490572..09a24413d940 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -165,7 +165,7 @@ static struct serio *parkbd_allocate_serio(void) { struct serio *serio; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (serio) { serio->id.type = parkbd_mode; serio->write = parkbd_write; diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 6b9abb2e18c9..78f47b0ca125 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -137,8 +137,8 @@ static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) if (ret) goto disable; - ps2if = kzalloc(sizeof(*ps2if), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + ps2if = kzalloc_obj(*ps2if); + serio = kzalloc_obj(*serio); if (!ps2if || !serio) { ret = -ENOMEM; goto release; diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index 93769910ce24..6cde0d88c6f4 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -50,7 +50,7 @@ * interrupt interval should be ~60us. Let's allow +/- 20us for frequency * deviations and interrupt latency. * - * The data line must be samples after ~30us to 50us after the falling edge, + * The data line must be sampled after ~30us to 50us after the falling edge, * since the device updates the data line at the rising edge. * * ___ ______ ______ ______ ___ @@ -405,7 +405,7 @@ static int ps2_gpio_probe(struct platform_device *pdev) int error; drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!drvdata || !serio) { error = -ENOMEM; goto err_free_serio; diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c index b96cee52fc52..27d554b59658 100644 --- a/drivers/input/serio/ps2mult.c +++ b/drivers/input/serio/ps2mult.c @@ -122,7 +122,7 @@ static int ps2mult_create_port(struct ps2mult *psm, int i) struct serio *mx_serio = psm->mx_serio; struct serio *serio; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; @@ -160,7 +160,7 @@ static int ps2mult_connect(struct serio *serio, struct serio_driver *drv) if (!serio->write) return -EINVAL; - psm = kzalloc(sizeof(*psm), GFP_KERNEL); + psm = kzalloc_obj(*psm); if (!psm) return -ENOMEM; diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index ae55c4de092f..2f553efbe649 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -102,8 +102,8 @@ static int q40kbd_probe(struct platform_device *pdev) struct serio *port; int error; - q40kbd = kzalloc(sizeof(*q40kbd), GFP_KERNEL); - port = kzalloc(sizeof(*port), GFP_KERNEL); + q40kbd = kzalloc_obj(*q40kbd); + port = kzalloc_obj(*port); if (!q40kbd || !port) { error = -ENOMEM; goto err_free_mem; diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index c65c552b0c45..4d817850ba3b 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -108,8 +108,8 @@ static int rpckbd_probe(struct platform_device *dev) if (tx_irq < 0) return tx_irq; - serio = kzalloc(sizeof(*serio), GFP_KERNEL); - rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL); + serio = kzalloc_obj(*serio); + rpckbd = kzalloc_obj(*rpckbd); if (!serio || !rpckbd) { kfree(rpckbd); kfree(serio); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 375c6f5f905c..e3a463c157d1 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -254,8 +254,8 @@ static int ps2_probe(struct sa1111_dev *dev) struct serio *serio; int ret; - ps2if = kzalloc(sizeof(*ps2if), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + ps2if = kzalloc_obj(*ps2if); + serio = kzalloc_obj(*serio); if (!ps2if || !serio) { ret = -ENOMEM; goto free; diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 4468018cef66..54dd26249b02 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/export.h> #include <linux/stddef.h> #include <linux/module.h> #include <linux/serio.h> @@ -243,7 +244,7 @@ static int serio_queue_event(void *object, struct module *owner, } } - event = kmalloc(sizeof(*event), GFP_ATOMIC); + event = kmalloc_obj(*event, GFP_ATOMIC); if (!event) { pr_err("Not enough memory to queue event %d\n", event_type); return -ENOMEM; diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c index 4d6395088986..a7ccedfa459c 100644 --- a/drivers/input/serio/serio_raw.c +++ b/drivers/input/serio/serio_raw.c @@ -270,7 +270,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv) struct serio_raw *serio_raw; int err; - serio_raw = kzalloc(sizeof(*serio_raw), GFP_KERNEL); + serio_raw = kzalloc_obj(*serio_raw); if (!serio_raw) { dev_dbg(&serio->dev, "can't allocate memory for a device\n"); return -ENOMEM; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 74ac88796187..cabe3876c168 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -78,7 +78,7 @@ static int serport_ldisc_open(struct tty_struct *tty) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - serport = kzalloc(sizeof(*serport), GFP_KERNEL); + serport = kzalloc_obj(*serport); if (!serport) return -ENOMEM; @@ -159,7 +159,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serport->serio = serio = kzalloc(sizeof(*serio), GFP_KERNEL); + serport->serio = serio = kzalloc_obj(*serio); if (!serio) return -ENOMEM; diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c index 524929ce1cae..a9812789771c 100644 --- a/drivers/input/serio/sun4i-ps2.c +++ b/drivers/input/serio/sun4i-ps2.c @@ -209,8 +209,8 @@ static int sun4i_ps2_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int error; - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + drvdata = kzalloc_obj(*drvdata); + serio = kzalloc_obj(*serio); if (!drvdata || !serio) { error = -ENOMEM; goto err_free_mem; diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c index 7f627b08055e..91cb7a177b2d 100644 --- a/drivers/input/serio/userio.c +++ b/drivers/input/serio/userio.c @@ -73,7 +73,7 @@ static int userio_device_write(struct serio *id, unsigned char val) static int userio_char_open(struct inode *inode, struct file *file) { struct userio_device *userio __free(kfree) = - kzalloc(sizeof(*userio), GFP_KERNEL); + kzalloc_obj(*userio); if (!userio) return -ENOMEM; @@ -81,7 +81,7 @@ static int userio_char_open(struct inode *inode, struct file *file) spin_lock_init(&userio->buf_lock); init_waitqueue_head(&userio->waitq); - userio->serio = kzalloc(sizeof(*userio->serio), GFP_KERNEL); + userio->serio = kzalloc_obj(*userio->serio); if (!userio->serio) return -ENOMEM; diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 01433f0b48f1..411d55ca1a66 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -247,8 +247,8 @@ static int xps2_of_probe(struct platform_device *ofdev) return -ENODEV; } - drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); - serio = kzalloc(sizeof(*serio), GFP_KERNEL); + drvdata = kzalloc_obj(*drvdata); + serio = kzalloc_obj(*serio); if (!drvdata || !serio) { error = -ENOMEM; goto failed1; diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index 25bf8be6e711..164f8fcfd1aa 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -10,6 +10,7 @@ * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> */ +#include <linux/export.h> #include <linux/input.h> #include <linux/input/sparse-keymap.h> #include <linux/module.h> @@ -176,8 +177,7 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), - GFP_KERNEL); + map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL); if (!map) return -ENOMEM; diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c index 0ac16f32b31f..ba79dff21aac 100644 --- a/drivers/input/tablet/acecad.c +++ b/drivers/input/tablet/acecad.c @@ -129,7 +129,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); maxp = usb_maxpacket(dev, pipe); - acecad = kzalloc(sizeof(*acecad), GFP_KERNEL); + acecad = kzalloc_obj(*acecad); input_dev = input_allocate_device(); if (!acecad || !input_dev) { err = -ENOMEM; diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 2b3fbb0455d5..c850b5890070 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -57,6 +57,7 @@ * http://aiptektablet.sourceforge.net. */ +#include <linux/hid.h> #include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -164,8 +165,6 @@ #define USB_VENDOR_ID_AIPTEK 0x08ca #define USB_VENDOR_ID_KYE 0x0458 -#define USB_REQ_GET_REPORT 0x01 -#define USB_REQ_SET_REPORT 0x09 /* PointerMode codes */ @@ -658,6 +657,8 @@ static void aiptek_irq(struct urb *urb) pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1; + if (macro >= ARRAY_SIZE(macroKeyEvents)) + macro = -1; z = get_unaligned_le16(data + 4); if (dv) { @@ -699,7 +700,9 @@ static void aiptek_irq(struct urb *urb) left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0; right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0; middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0; - macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0; + macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : -1; + if (macro >= ARRAY_SIZE(macroKeyEvents)) + macro = -1; if (dv) { /* If the selected tool changed, reset the old @@ -737,11 +740,11 @@ static void aiptek_irq(struct urb *urb) */ else if (data[0] == 6) { macro = get_unaligned_le16(data + 1); - if (macro > 0) { + if (macro > 0 && macro - 1 < ARRAY_SIZE(macroKeyEvents)) { input_report_key(inputdev, macroKeyEvents[macro - 1], 0); } - if (macro < 25) { + if (macro + 1 < ARRAY_SIZE(macroKeyEvents)) { input_report_key(inputdev, macroKeyEvents[macro + 1], 0); } @@ -760,7 +763,8 @@ static void aiptek_irq(struct urb *urb) aiptek->curSetting.toolMode; } - input_report_key(inputdev, macroKeyEvents[macro], 1); + if (macro < ARRAY_SIZE(macroKeyEvents)) + input_report_key(inputdev, macroKeyEvents[macro], 1); input_report_abs(inputdev, ABS_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN); input_sync(inputdev); @@ -856,7 +860,7 @@ aiptek_set_report(struct aiptek *aiptek, return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - USB_REQ_SET_REPORT, + HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, (report_type << 8) + report_id, aiptek->ifnum, buffer, size, 5000); @@ -871,7 +875,7 @@ aiptek_get_report(struct aiptek *aiptek, return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), - USB_REQ_GET_REPORT, + HID_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, (report_type << 8) + report_id, aiptek->ifnum, buffer, size, 5000); @@ -1673,7 +1677,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) */ speeds[0] = programmableDelay; - aiptek = kzalloc(sizeof(*aiptek), GFP_KERNEL); + aiptek = kzalloc_obj(*aiptek); inputdev = input_allocate_device(); if (!aiptek || !inputdev) { dev_warn(&intf->dev, diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c index 42c1e5eaddd5..fd5a7e761dcc 100644 --- a/drivers/input/tablet/hanwang.c +++ b/drivers/input/tablet/hanwang.c @@ -322,7 +322,7 @@ static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id if (intf->cur_altsetting->desc.bNumEndpoints < 1) return -ENODEV; - hanwang = kzalloc(sizeof(*hanwang), GFP_KERNEL); + hanwang = kzalloc_obj(*hanwang); input_dev = input_allocate_device(); if (!hanwang || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 794caa102909..6ce70c8e2d7c 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -121,7 +121,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; - kbtab = kzalloc(sizeof(*kbtab), GFP_KERNEL); + kbtab = kzalloc_obj(*kbtab); input_dev = input_allocate_device(); if (!kbtab || !input_dev) goto fail1; diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c index 8d6b71d59793..85390ae42307 100644 --- a/drivers/input/tablet/pegasus_notetaker.c +++ b/drivers/input/tablet/pegasus_notetaker.c @@ -36,6 +36,7 @@ * T Tip */ +#include <linux/hid.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/input.h> @@ -44,10 +45,6 @@ #include <linux/workqueue.h> #include <linux/mutex.h> -/* USB HID defines */ -#define USB_REQ_GET_REPORT 0x01 -#define USB_REQ_SET_REPORT 0x09 - #define USB_VENDOR_ID_PEGASUSTECH 0x0e20 #define USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100 0x0101 @@ -63,6 +60,9 @@ #define BUTTON_PRESSED 0xb5 #define COMMAND_VERSION 0xa9 +/* 1 Status + 1 Color + 2 X + 2 Y = 6 bytes */ +#define NOTETAKER_PACKET_SIZE 6 + /* in xy data packet */ #define BATTERY_NO_REPORT 0x40 #define BATTERY_LOW 0x41 @@ -105,7 +105,7 @@ static int pegasus_control_msg(struct pegasus *pegasus, u8 *data, int len) result = usb_control_msg(pegasus->usbdev, usb_sndctrlpipe(pegasus->usbdev, 0), - USB_REQ_SET_REPORT, + HID_REQ_SET_REPORT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, cmd_buf, sizeof_buf, USB_CTRL_SET_TIMEOUT); @@ -290,7 +290,7 @@ static int pegasus_probe(struct usb_interface *intf, endpoint = &intf->cur_altsetting->endpoint[0].desc; - pegasus = kzalloc(sizeof(*pegasus), GFP_KERNEL); + pegasus = kzalloc_obj(*pegasus); input_dev = input_allocate_device(); if (!pegasus || !input_dev) { error = -ENOMEM; @@ -311,6 +311,12 @@ static int pegasus_probe(struct usb_interface *intf, } pegasus->data_len = usb_maxpacket(dev, pipe); + if (pegasus->data_len < NOTETAKER_PACKET_SIZE) { + dev_err(&intf->dev, "packet size is too small (%d)\n", + pegasus->data_len); + error = -EINVAL; + goto err_free_mem; + } pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL, &pegasus->data_dma); diff --git a/drivers/input/tablet/wacom_serial4.c b/drivers/input/tablet/wacom_serial4.c index cf7cea77dabc..bc0c77e5487f 100644 --- a/drivers/input/tablet/wacom_serial4.c +++ b/drivers/input/tablet/wacom_serial4.c @@ -521,7 +521,7 @@ static int wacom_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err = -ENOMEM; - wacom = kzalloc(sizeof(*wacom), GFP_KERNEL); + wacom = kzalloc_obj(*wacom); input_dev = input_allocate_device(); if (!wacom || !input_dev) goto free_device; diff --git a/drivers/input/touch-overlay.c b/drivers/input/touch-overlay.c new file mode 100644 index 000000000000..b9fd82c4829d --- /dev/null +++ b/drivers/input/touch-overlay.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Helper functions for overlay objects on touchscreens + * + * Copyright (c) 2023 Javier Carrasco <javier.carrasco@wolfvision.net> + */ + +#include <linux/export.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touch-overlay.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/property.h> + +struct touch_overlay_segment { + struct list_head list; + u32 x_origin; + u32 y_origin; + u32 x_size; + u32 y_size; + u32 key; + bool pressed; + int slot; +}; + +static int touch_overlay_get_segment(struct fwnode_handle *segment_node, + struct touch_overlay_segment *segment, + struct input_dev *input) +{ + int error; + + error = fwnode_property_read_u32(segment_node, "x-origin", + &segment->x_origin); + if (error) + return error; + + error = fwnode_property_read_u32(segment_node, "y-origin", + &segment->y_origin); + if (error) + return error; + + error = fwnode_property_read_u32(segment_node, "x-size", + &segment->x_size); + if (error) + return error; + + error = fwnode_property_read_u32(segment_node, "y-size", + &segment->y_size); + if (error) + return error; + + error = fwnode_property_read_u32(segment_node, "linux,code", + &segment->key); + if (!error) + input_set_capability(input, EV_KEY, segment->key); + else if (error != -EINVAL) + return error; + + return 0; +} + +/** + * touch_overlay_map - map overlay objects from the device tree and set + * key capabilities if buttons are defined. + * @list: pointer to the list that will hold the segments + * @input: pointer to the already allocated input_dev + * + * Returns 0 on success and error number otherwise. + * + * If buttons are defined, key capabilities are set accordingly. + */ +int touch_overlay_map(struct list_head *list, struct input_dev *input) +{ + struct fwnode_handle *fw_segment; + struct device *dev = input->dev.parent; + struct touch_overlay_segment *segment; + int error; + + struct fwnode_handle *overlay __free(fwnode_handle) = + device_get_named_child_node(dev, "touch-overlay"); + if (!overlay) + return 0; + + fwnode_for_each_available_child_node(overlay, fw_segment) { + segment = devm_kzalloc(dev, sizeof(*segment), GFP_KERNEL); + if (!segment) { + fwnode_handle_put(fw_segment); + return -ENOMEM; + } + error = touch_overlay_get_segment(fw_segment, segment, input); + if (error) { + fwnode_handle_put(fw_segment); + return error; + } + list_add_tail(&segment->list, list); + } + + return 0; +} +EXPORT_SYMBOL(touch_overlay_map); + +/** + * touch_overlay_get_touchscreen_abs - get abs size from the touchscreen area. + * @list: pointer to the list that holds the segments + * @x: horizontal abs + * @y: vertical abs + */ +void touch_overlay_get_touchscreen_abs(struct list_head *list, u16 *x, u16 *y) +{ + struct touch_overlay_segment *segment; + struct list_head *ptr; + + list_for_each(ptr, list) { + segment = list_entry(ptr, struct touch_overlay_segment, list); + if (!segment->key) { + *x = segment->x_size - 1; + *y = segment->y_size - 1; + break; + } + } +} +EXPORT_SYMBOL(touch_overlay_get_touchscreen_abs); + +static bool touch_overlay_segment_event(struct touch_overlay_segment *seg, + struct input_mt_pos *pos) +{ + if (pos->x >= seg->x_origin && pos->x < (seg->x_origin + seg->x_size) && + pos->y >= seg->y_origin && pos->y < (seg->y_origin + seg->y_size)) + return true; + + return false; +} + +/** + * touch_overlay_mapped_touchscreen - check if a touchscreen area is mapped + * @list: pointer to the list that holds the segments + * + * Returns true if a touchscreen area is mapped or false otherwise. + */ +bool touch_overlay_mapped_touchscreen(struct list_head *list) +{ + struct touch_overlay_segment *segment; + struct list_head *ptr; + + list_for_each(ptr, list) { + segment = list_entry(ptr, struct touch_overlay_segment, list); + if (!segment->key) + return true; + } + + return false; +} +EXPORT_SYMBOL(touch_overlay_mapped_touchscreen); + +static bool touch_overlay_event_on_ts(struct list_head *list, + struct input_mt_pos *pos) +{ + struct touch_overlay_segment *segment; + struct list_head *ptr; + + list_for_each(ptr, list) { + segment = list_entry(ptr, struct touch_overlay_segment, list); + if (segment->key) + continue; + + if (touch_overlay_segment_event(segment, pos)) { + pos->x -= segment->x_origin; + pos->y -= segment->y_origin; + return true; + } + /* ignore touch events outside the defined area */ + return false; + } + + return true; +} + +static bool touch_overlay_button_event(struct input_dev *input, + struct touch_overlay_segment *segment, + struct input_mt_pos *pos, int slot) +{ + struct input_mt *mt = input->mt; + struct input_mt_slot *s = &mt->slots[slot]; + bool button_contact = touch_overlay_segment_event(segment, pos); + + if (segment->slot == slot && segment->pressed) { + /* sliding out of the button releases it */ + if (!button_contact) { + input_report_key(input, segment->key, false); + segment->pressed = false; + /* keep available for a possible touch event */ + return false; + } + /* ignore sliding on the button while pressed */ + s->frame = mt->frame; + return true; + } else if (button_contact) { + input_report_key(input, segment->key, true); + s->frame = mt->frame; + segment->slot = slot; + segment->pressed = true; + return true; + } + + return false; +} + +/** + * touch_overlay_sync_frame - update the status of the segments and report + * buttons whose tracked slot is unused. + * @list: pointer to the list that holds the segments + * @input: pointer to the input device associated to the contact + */ +void touch_overlay_sync_frame(struct list_head *list, struct input_dev *input) +{ + struct touch_overlay_segment *segment; + struct input_mt *mt = input->mt; + struct input_mt_slot *s; + struct list_head *ptr; + + list_for_each(ptr, list) { + segment = list_entry(ptr, struct touch_overlay_segment, list); + if (!segment->key) + continue; + + s = &mt->slots[segment->slot]; + if (!input_mt_is_used(mt, s) && segment->pressed) { + input_report_key(input, segment->key, false); + segment->pressed = false; + } + } +} +EXPORT_SYMBOL(touch_overlay_sync_frame); + +/** + * touch_overlay_process_contact - process contacts according to the overlay + * mapping. This function acts as a filter to release the calling driver + * from the contacts that are either related to overlay buttons or out of the + * overlay touchscreen area, if defined. + * @list: pointer to the list that holds the segments + * @input: pointer to the input device associated to the contact + * @pos: pointer to the contact position + * @slot: slot associated to the contact (0 if multitouch is not supported) + * + * Returns true if the contact was processed (reported for valid key events + * and dropped for contacts outside the overlay touchscreen area) or false + * if the contact must be processed by the caller. In that case this function + * shifts the (x,y) coordinates to the overlay touchscreen axis if required. + */ +bool touch_overlay_process_contact(struct list_head *list, + struct input_dev *input, + struct input_mt_pos *pos, int slot) +{ + struct touch_overlay_segment *segment; + struct list_head *ptr; + + /* + * buttons must be prioritized over overlay touchscreens to account for + * overlappings e.g. a button inside the touchscreen area. + */ + list_for_each(ptr, list) { + segment = list_entry(ptr, struct touch_overlay_segment, list); + if (segment->key && + touch_overlay_button_event(input, segment, pos, slot)) + return true; + } + + /* + * valid contacts on the overlay touchscreen are left for the client + * to be processed/reported according to its (possibly) unique features. + */ + return !touch_overlay_event_on_ts(list, pos); +} +EXPORT_SYMBOL(touch_overlay_process_contact); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Helper functions for overlay objects on touch devices"); diff --git a/drivers/input/touchscreen.c b/drivers/input/touchscreen.c index 4620e20d0190..d699b24bb548 100644 --- a/drivers/input/touchscreen.c +++ b/drivers/input/touchscreen.c @@ -6,6 +6,7 @@ * Copyright (c) 2014 Sebastian Reichel <sre@kernel.org> */ +#include <linux/export.h> #include <linux/property.h> #include <linux/input.h> #include <linux/input/mt.h> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1a03de7fcfa6..aeaf9a9cbb41 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -103,6 +103,18 @@ config TOUCHSCREEN_ADC To compile this driver as a module, choose M here: the module will be called resistive-adc-touch.ko. +config TOUCHSCREEN_APPLE_Z2 + tristate "Apple Z2 touchscreens" + depends on SPI && (ARCH_APPLE || COMPILE_TEST) + help + Say Y here if you have an ARM Apple device with + a touchscreen or a touchbar. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called apple_z2. + config TOUCHSCREEN_AR1021_I2C tristate "Microchip AR1020/1021 i2c touchscreen" depends on I2C && OF @@ -429,6 +441,16 @@ config TOUCHSCREEN_HIDEEP To compile this driver as a module, choose M here : the module will be called hideep_ts. +config TOUCHSCREEN_HIMAX_HX852X + tristate "Himax HX852x(ES) touchscreen" + depends on I2C + help + Say Y here if you have a Himax HX852x(ES) touchscreen. + If unsure, say N. + + To compile this driver as a module, choose M here: the module + will be called himax_hx852x. + config TOUCHSCREEN_HYCON_HY46XX tristate "Hycon hy46xx touchscreen support" depends on I2C @@ -453,6 +475,18 @@ config TOUCHSCREEN_HYNITRON_CSTXXX To compile this driver as a module, choose M here: the module will be called hynitron-cstxxx. +config TOUCHSCREEN_HYNITRON_CST816X + tristate "Hynitron CST816x touchscreen" + depends on I2C + help + Say Y here if you have a touchscreen using a Hynitron + CST816x series touchscreen controller. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called hynitron-cst816x. + config TOUCHSCREEN_ILI210X tristate "Ilitek ILI210X based touchscreen" depends on I2C @@ -689,18 +723,6 @@ config TOUCHSCREEN_INEXIO To compile this driver as a module, choose M here: the module will be called inexio. -config TOUCHSCREEN_MK712 - tristate "ICS MicroClock MK712 touchscreen" - depends on ISA - help - Say Y here if you have the ICS MicroClock MK712 touchscreen - controller chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mk712. - config TOUCHSCREEN_HP600 tristate "HP Jornada 6xx touchscreen" depends on SH_HP6XX && SH_ADC diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 82bc837ca01e..f2b002abebe8 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o +obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o @@ -48,7 +49,9 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o +obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CST816X) += hynitron-cst816x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o @@ -65,7 +68,6 @@ obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o -obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c index a0598e9c7aff..cc39057d0117 100644 --- a/drivers/input/touchscreen/ad7877.c +++ b/drivers/input/touchscreen/ad7877.c @@ -201,7 +201,7 @@ static int ad7877_read(struct spi_device *spi, u16 reg) struct ser_req *req; int status, ret; - req = kzalloc(sizeof *req, GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -232,7 +232,7 @@ static int ad7877_write(struct spi_device *spi, u16 reg, u16 val) struct ser_req *req; int status; - req = kzalloc(sizeof *req, GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -259,7 +259,7 @@ static int ad7877_read_adc(struct spi_device *spi, unsigned command) int sample; int i; - req = kzalloc(sizeof *req, GFP_KERNEL); + req = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -375,18 +375,15 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts) static void ad7877_timer(struct timer_list *t) { - struct ad7877 *ts = from_timer(ts, t, timer); - unsigned long flags; + struct ad7877 *ts = timer_container_of(ts, t, timer); - spin_lock_irqsave(&ts->lock, flags); + guard(spinlock_irqsave)(&ts->lock); ad7877_ts_event_release(ts); - spin_unlock_irqrestore(&ts->lock, flags); } static irqreturn_t ad7877_irq(int irq, void *handle) { struct ad7877 *ts = handle; - unsigned long flags; int error; error = spi_sync(ts->spi, &ts->msg); @@ -395,11 +392,13 @@ static irqreturn_t ad7877_irq(int irq, void *handle) goto out; } - spin_lock_irqsave(&ts->lock, flags); - error = ad7877_process_data(ts); - if (!error) + scoped_guard(spinlock_irqsave, &ts->lock) { + error = ad7877_process_data(ts); + if (error) + goto out; + mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); - spin_unlock_irqrestore(&ts->lock, flags); + } out: return IRQ_HANDLED; @@ -409,13 +408,13 @@ static void ad7877_disable(void *data) { struct ad7877 *ts = data; - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); if (!ts->disabled) { ts->disabled = true; disable_irq(ts->spi->irq); - if (del_timer_sync(&ts->timer)) + if (timer_delete_sync(&ts->timer)) ad7877_ts_event_release(ts); } @@ -423,20 +422,16 @@ static void ad7877_disable(void *data) * We know the chip's in lowpower mode since we always * leave it that way after every request */ - - mutex_unlock(&ts->mutex); } static void ad7877_enable(struct ad7877 *ts) { - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); if (ts->disabled) { ts->disabled = false; enable_irq(ts->spi->irq); } - - mutex_unlock(&ts->mutex); } #define SHOW(name) static ssize_t \ @@ -509,10 +504,9 @@ static ssize_t ad7877_dac_store(struct device *dev, if (error) return error; - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); ts->dac = val & 0xFF; ad7877_write(ts->spi, AD7877_REG_DAC, (ts->dac << 4) | AD7877_DAC_CONF); - mutex_unlock(&ts->mutex); return count; } @@ -539,11 +533,10 @@ static ssize_t ad7877_gpio3_store(struct device *dev, if (error) return error; - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); ts->gpio3 = !!val; ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA | (ts->gpio4 << 4) | (ts->gpio3 << 5)); - mutex_unlock(&ts->mutex); return count; } @@ -570,11 +563,10 @@ static ssize_t ad7877_gpio4_store(struct device *dev, if (error) return error; - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); ts->gpio4 = !!val; ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA | (ts->gpio4 << 4) | (ts->gpio3 << 5)); - mutex_unlock(&ts->mutex); return count; } diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index e5d69bf2276e..31d2a3029d5f 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -22,6 +22,7 @@ #include <linux/device.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/input.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -237,7 +238,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts) static void ad7879_timer(struct timer_list *t) { - struct ad7879 *ts = from_timer(ts, t, timer); + struct ad7879 *ts = timer_container_of(ts, t, timer); ad7879_ts_event_release(ts); } @@ -273,7 +274,7 @@ static void __ad7879_disable(struct ad7879 *ts) AD7879_PM(AD7879_PM_SHUTDOWN); disable_irq(ts->irq); - if (del_timer_sync(&ts->timer)) + if (timer_delete_sync(&ts->timer)) ad7879_ts_event_release(ts); ad7879_write(ts, AD7879_REG_CTRL2, reg); @@ -304,15 +305,13 @@ static int __maybe_unused ad7879_suspend(struct device *dev) { struct ad7879 *ts = dev_get_drvdata(dev); - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); if (!ts->suspended && !ts->disabled && input_device_enabled(ts->input)) __ad7879_disable(ts); ts->suspended = true; - mutex_unlock(&ts->input->mutex); - return 0; } @@ -320,15 +319,13 @@ static int __maybe_unused ad7879_resume(struct device *dev) { struct ad7879 *ts = dev_get_drvdata(dev); - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); if (ts->suspended && !ts->disabled && input_device_enabled(ts->input)) __ad7879_enable(ts); ts->suspended = false; - mutex_unlock(&ts->input->mutex); - return 0; } @@ -337,7 +334,7 @@ EXPORT_SYMBOL(ad7879_pm_ops); static void ad7879_toggle(struct ad7879 *ts, bool disable) { - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); if (!ts->suspended && input_device_enabled(ts->input)) { @@ -351,8 +348,6 @@ static void ad7879_toggle(struct ad7879 *ts, bool disable) } ts->disabled = disable; - - mutex_unlock(&ts->input->mutex); } static ssize_t ad7879_disable_show(struct device *dev, @@ -402,23 +397,20 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) { struct ad7879 *ts = gpiochip_get_data(chip); - int err; - mutex_lock(&ts->mutex); - ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL; - err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); - mutex_unlock(&ts->mutex); + guard(mutex)(&ts->mutex); - return err; + ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL; + return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); } static int ad7879_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level) { struct ad7879 *ts = gpiochip_get_data(chip); - int err; - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); + ts->cmd_crtl2 &= ~AD7879_GPIODIR; ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL; if (level) @@ -426,37 +418,33 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip, else ts->cmd_crtl2 &= ~AD7879_GPIO_DATA; - err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); - mutex_unlock(&ts->mutex); - - return err; + return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); } -static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned int gpio) { struct ad7879 *ts = gpiochip_get_data(chip); u16 val; - mutex_lock(&ts->mutex); - val = ad7879_read(ts, AD7879_REG_CTRL2); - mutex_unlock(&ts->mutex); + guard(mutex)(&ts->mutex); + val = ad7879_read(ts, AD7879_REG_CTRL2); return !!(val & AD7879_GPIO_DATA); } -static void ad7879_gpio_set_value(struct gpio_chip *chip, - unsigned gpio, int value) +static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio, + int value) { struct ad7879 *ts = gpiochip_get_data(chip); - mutex_lock(&ts->mutex); + guard(mutex)(&ts->mutex); + if (value) ts->cmd_crtl2 |= AD7879_GPIO_DATA; else ts->cmd_crtl2 &= ~AD7879_GPIO_DATA; - ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); - mutex_unlock(&ts->mutex); + return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2); } static int ad7879_gpio_add(struct ad7879 *ts) diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 67264c5b49cb..4b39f7212d35 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -289,7 +289,7 @@ static void __ads7846_enable(struct ads7846 *ts) static void ads7846_disable(struct ads7846 *ts) { - mutex_lock(&ts->lock); + guard(mutex)(&ts->lock); if (!ts->disabled) { @@ -298,13 +298,11 @@ static void ads7846_disable(struct ads7846 *ts) ts->disabled = true; } - - mutex_unlock(&ts->lock); } static void ads7846_enable(struct ads7846 *ts) { - mutex_lock(&ts->lock); + guard(mutex)(&ts->lock); if (ts->disabled) { @@ -313,8 +311,6 @@ static void ads7846_enable(struct ads7846 *ts) if (!ts->suspended) __ads7846_enable(ts); } - - mutex_unlock(&ts->lock); } /*--------------------------------------------------------------------------*/ @@ -354,10 +350,9 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); struct ads7846 *ts = dev_get_drvdata(dev); - struct ser_req *req; int status; - req = kzalloc(sizeof *req, GFP_KERNEL); + struct ser_req *req __free(kfree) = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -418,11 +413,11 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) CS_CHANGE(req->xfer[7]); spi_message_add_tail(&req->xfer[7], &req->msg); - mutex_lock(&ts->lock); - ads7846_stop(ts); - status = spi_sync(spi, &req->msg); - ads7846_restart(ts); - mutex_unlock(&ts->lock); + scoped_guard(mutex, &ts->lock) { + ads7846_stop(ts); + status = spi_sync(spi, &req->msg); + ads7846_restart(ts); + } if (status == 0) { /* on-wire is a must-ignore bit, a BE12 value, then padding */ @@ -431,7 +426,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) status &= 0x0fff; } - kfree(req); return status; } @@ -439,10 +433,9 @@ static int ads7845_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); struct ads7846 *ts = dev_get_drvdata(dev); - struct ads7845_ser_req *req; int status; - req = kzalloc(sizeof *req, GFP_KERNEL); + struct ads7845_ser_req *req __free(kfree) = kzalloc_obj(*req); if (!req) return -ENOMEM; @@ -454,11 +447,11 @@ static int ads7845_read12_ser(struct device *dev, unsigned command) req->xfer[0].len = 3; spi_message_add_tail(&req->xfer[0], &req->msg); - mutex_lock(&ts->lock); - ads7846_stop(ts); - status = spi_sync(spi, &req->msg); - ads7846_restart(ts); - mutex_unlock(&ts->lock); + scoped_guard(mutex, &ts->lock) { + ads7846_stop(ts); + status = spi_sync(spi, &req->msg); + ads7846_restart(ts); + } if (status == 0) { /* BE12 value, then padding */ @@ -467,7 +460,6 @@ static int ads7845_read12_ser(struct device *dev, unsigned command) status &= 0x0fff; } - kfree(req); return status; } @@ -966,7 +958,7 @@ static int ads7846_suspend(struct device *dev) { struct ads7846 *ts = dev_get_drvdata(dev); - mutex_lock(&ts->lock); + guard(mutex)(&ts->lock); if (!ts->suspended) { @@ -979,8 +971,6 @@ static int ads7846_suspend(struct device *dev) ts->suspended = true; } - mutex_unlock(&ts->lock); - return 0; } @@ -988,7 +978,7 @@ static int ads7846_resume(struct device *dev) { struct ads7846 *ts = dev_get_drvdata(dev); - mutex_lock(&ts->lock); + guard(mutex)(&ts->lock); if (ts->suspended) { @@ -1001,8 +991,6 @@ static int ads7846_resume(struct device *dev) __ads7846_enable(ts); } - mutex_unlock(&ts->lock); - return 0; } diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c new file mode 100644 index 000000000000..271ababf0ad5 --- /dev/null +++ b/drivers/input/touchscreen/apple_z2.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Apple Z2 touchscreen driver + * + * Copyright (C) The Asahi Linux Contributors + */ + +#include <linux/delay.h> +#include <linux/firmware.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/spi/spi.h> +#include <linux/unaligned.h> + +#define APPLE_Z2_NUM_FINGERS_OFFSET 16 +#define APPLE_Z2_FINGERS_OFFSET 24 +#define APPLE_Z2_TOUCH_STARTED 3 +#define APPLE_Z2_TOUCH_MOVED 4 +#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB +#define APPLE_Z2_REPLY_INTERRUPT_DATA 0xE1 +#define APPLE_Z2_HBPP_CMD_BLOB 0x3001 +#define APPLE_Z2_FW_MAGIC 0x5746325A +#define LOAD_COMMAND_INIT_PAYLOAD 0 +#define LOAD_COMMAND_SEND_BLOB 1 +#define LOAD_COMMAND_SEND_CALIBRATION 2 +#define CAL_PROP_NAME "apple,z2-cal-blob" + +struct apple_z2 { + struct spi_device *spidev; + struct gpio_desc *reset_gpio; + struct input_dev *input_dev; + struct completion boot_irq; + bool booted; + int index_parity; + struct touchscreen_properties props; + const char *fw_name; + u8 *tx_buf; + u8 *rx_buf; +}; + +struct apple_z2_finger { + u8 finger; + u8 state; + __le16 unknown2; + __le16 abs_x; + __le16 abs_y; + __le16 rel_x; + __le16 rel_y; + __le16 tool_major; + __le16 tool_minor; + __le16 orientation; + __le16 touch_major; + __le16 touch_minor; + __le16 unused[2]; + __le16 pressure; + __le16 multi; +} __packed; + +struct apple_z2_hbpp_blob_hdr { + __le16 cmd; + __le16 len; + __le32 addr; + __le16 checksum; +}; + +struct apple_z2_fw_hdr { + __le32 magic; + __le32 version; +}; + +struct apple_z2_read_interrupt_cmd { + u8 cmd; + u8 counter; + u8 unused[12]; + __le16 checksum; +}; + +static void apple_z2_parse_touches(struct apple_z2 *z2, + const u8 *msg, size_t msg_len) +{ + int i; + int nfingers; + int slot; + int slot_valid; + struct apple_z2_finger *fingers; + + if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET) + return; + nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET]; + fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET); + for (i = 0; i < nfingers; i++) { + slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger); + if (slot < 0) { + dev_warn(&z2->spidev->dev, "unable to get slot for finger\n"); + continue; + } + slot_valid = fingers[i].state == APPLE_Z2_TOUCH_STARTED || + fingers[i].state == APPLE_Z2_TOUCH_MOVED; + input_mt_slot(z2->input_dev, slot); + if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid)) + continue; + touchscreen_report_pos(z2->input_dev, &z2->props, + le16_to_cpu(fingers[i].abs_x), + le16_to_cpu(fingers[i].abs_y), + true); + input_report_abs(z2->input_dev, ABS_MT_WIDTH_MAJOR, + le16_to_cpu(fingers[i].tool_major)); + input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR, + le16_to_cpu(fingers[i].tool_minor)); + input_report_abs(z2->input_dev, ABS_MT_ORIENTATION, + le16_to_cpu(fingers[i].orientation)); + input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR, + le16_to_cpu(fingers[i].touch_major)); + input_report_abs(z2->input_dev, ABS_MT_TOUCH_MINOR, + le16_to_cpu(fingers[i].touch_minor)); + } + input_mt_sync_frame(z2->input_dev); + input_sync(z2->input_dev); +} + +static int apple_z2_read_packet(struct apple_z2 *z2) +{ + struct apple_z2_read_interrupt_cmd *len_cmd = (void *)z2->tx_buf; + struct spi_transfer xfer; + int error; + size_t pkt_len; + + memset(&xfer, 0, sizeof(xfer)); + len_cmd->cmd = APPLE_Z2_CMD_READ_INTERRUPT_DATA; + len_cmd->counter = z2->index_parity + 1; + len_cmd->checksum = + cpu_to_le16(APPLE_Z2_CMD_READ_INTERRUPT_DATA + len_cmd->counter); + z2->index_parity = !z2->index_parity; + xfer.tx_buf = z2->tx_buf; + xfer.rx_buf = z2->rx_buf; + xfer.len = sizeof(*len_cmd); + + error = spi_sync_transfer(z2->spidev, &xfer, 1); + if (error) + return error; + + if (z2->rx_buf[0] != APPLE_Z2_REPLY_INTERRUPT_DATA) + return 0; + + pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc; + + error = spi_read(z2->spidev, z2->rx_buf, pkt_len); + if (error) + return error; + + apple_z2_parse_touches(z2, z2->rx_buf + 5, pkt_len - 5); + + return 0; +} + +static irqreturn_t apple_z2_irq(int irq, void *data) +{ + struct apple_z2 *z2 = data; + + if (unlikely(!z2->booted)) + complete(&z2->boot_irq); + else + apple_z2_read_packet(z2); + + return IRQ_HANDLED; +} + +/* Build calibration blob, caller is responsible for freeing the blob data. */ +static const u8 *apple_z2_build_cal_blob(struct apple_z2 *z2, + u32 address, size_t *size) +{ + u8 *cal_data; + int cal_size; + size_t blob_size; + u32 checksum; + u16 checksum_hdr; + int i; + struct apple_z2_hbpp_blob_hdr *hdr; + int error; + + if (!device_property_present(&z2->spidev->dev, CAL_PROP_NAME)) + return NULL; + + cal_size = device_property_count_u8(&z2->spidev->dev, CAL_PROP_NAME); + if (cal_size < 0) + return ERR_PTR(cal_size); + + blob_size = sizeof(struct apple_z2_hbpp_blob_hdr) + cal_size + sizeof(__le32); + u8 *blob_data __free(kfree) = kzalloc(blob_size, GFP_KERNEL); + if (!blob_data) + return ERR_PTR(-ENOMEM); + + hdr = (struct apple_z2_hbpp_blob_hdr *)blob_data; + hdr->cmd = cpu_to_le16(APPLE_Z2_HBPP_CMD_BLOB); + hdr->len = cpu_to_le16(round_up(cal_size, 4) / 4); + hdr->addr = cpu_to_le32(address); + + checksum_hdr = 0; + for (i = 2; i < 8; i++) + checksum_hdr += blob_data[i]; + hdr->checksum = cpu_to_le16(checksum_hdr); + + cal_data = blob_data + sizeof(struct apple_z2_hbpp_blob_hdr); + error = device_property_read_u8_array(&z2->spidev->dev, CAL_PROP_NAME, + cal_data, cal_size); + if (error) + return ERR_PTR(error); + + checksum = 0; + for (i = 0; i < cal_size; i++) + checksum += cal_data[i]; + put_unaligned_le32(checksum, cal_data + cal_size); + + *size = blob_size; + return no_free_ptr(blob_data); +} + +static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data, + u32 size, bool init) +{ + struct spi_message msg; + struct spi_transfer blob_xfer, ack_xfer; + int error; + + z2->tx_buf[0] = 0x1a; + z2->tx_buf[1] = 0xa1; + + spi_message_init(&msg); + memset(&blob_xfer, 0, sizeof(blob_xfer)); + memset(&ack_xfer, 0, sizeof(ack_xfer)); + + blob_xfer.tx_buf = data; + blob_xfer.len = size; + blob_xfer.bits_per_word = init ? 8 : 16; + spi_message_add_tail(&blob_xfer, &msg); + + ack_xfer.tx_buf = z2->tx_buf; + ack_xfer.len = 2; + spi_message_add_tail(&ack_xfer, &msg); + + reinit_completion(&z2->boot_irq); + error = spi_sync(z2->spidev, &msg); + if (error) + return error; + + /* Irq only happens sometimes, but the thing boots reliably nonetheless */ + wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)); + + return 0; +} + +static int apple_z2_upload_firmware(struct apple_z2 *z2) +{ + const struct apple_z2_fw_hdr *fw_hdr; + size_t fw_idx = sizeof(struct apple_z2_fw_hdr); + int error; + u32 load_cmd; + u32 address; + bool init; + size_t size; + + const struct firmware *fw __free(firmware) = NULL; + error = request_firmware(&fw, z2->fw_name, &z2->spidev->dev); + if (error) { + dev_err(&z2->spidev->dev, "unable to load firmware\n"); + return error; + } + + fw_hdr = (const struct apple_z2_fw_hdr *)fw->data; + if (le32_to_cpu(fw_hdr->magic) != APPLE_Z2_FW_MAGIC || le32_to_cpu(fw_hdr->version) != 1) { + dev_err(&z2->spidev->dev, "invalid firmware header\n"); + return -EINVAL; + } + + /* + * This will interrupt the upload half-way if the file is malformed + * As the device has no non-volatile storage to corrupt, and gets reset + * on boot anyway, this is fine. + */ + while (fw_idx < fw->size) { + if (fw->size - fw_idx < 8) { + dev_err(&z2->spidev->dev, "firmware malformed\n"); + return -EINVAL; + } + + load_cmd = le32_to_cpup((__force __le32 *)(fw->data + fw_idx)); + fw_idx += sizeof(u32); + if (load_cmd == LOAD_COMMAND_INIT_PAYLOAD || load_cmd == LOAD_COMMAND_SEND_BLOB) { + size = le32_to_cpup((__force __le32 *)(fw->data + fw_idx)); + fw_idx += sizeof(u32); + if (fw->size - fw_idx < size) { + dev_err(&z2->spidev->dev, "firmware malformed\n"); + return -EINVAL; + } + init = load_cmd == LOAD_COMMAND_INIT_PAYLOAD; + error = apple_z2_send_firmware_blob(z2, fw->data + fw_idx, + size, init); + if (error) + return error; + fw_idx += size; + } else if (load_cmd == LOAD_COMMAND_SEND_CALIBRATION) { + address = le32_to_cpup((__force __le32 *)(fw->data + fw_idx)); + fw_idx += sizeof(u32); + + const u8 *data __free(kfree) = + apple_z2_build_cal_blob(z2, address, &size); + if (IS_ERR(data)) + return PTR_ERR(data); + + if (data) { + error = apple_z2_send_firmware_blob(z2, data, size, false); + if (error) + return error; + } + } else { + dev_err(&z2->spidev->dev, "firmware malformed\n"); + return -EINVAL; + } + fw_idx = round_up(fw_idx, 4); + } + + + z2->booted = true; + apple_z2_read_packet(z2); + return 0; +} + +static int apple_z2_boot(struct apple_z2 *z2) +{ + int error; + + reinit_completion(&z2->boot_irq); + enable_irq(z2->spidev->irq); + gpiod_set_value(z2->reset_gpio, 0); + if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20))) + return -ETIMEDOUT; + + error = apple_z2_upload_firmware(z2); + if (error) { + gpiod_set_value(z2->reset_gpio, 1); + disable_irq(z2->spidev->irq); + return error; + } + + return 0; +} + +static int apple_z2_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct apple_z2 *z2; + int error; + + z2 = devm_kzalloc(dev, sizeof(*z2), GFP_KERNEL); + if (!z2) + return -ENOMEM; + + z2->tx_buf = devm_kzalloc(dev, sizeof(struct apple_z2_read_interrupt_cmd), GFP_KERNEL); + if (!z2->tx_buf) + return -ENOMEM; + /* 4096 will end up being rounded up to 8192 due to devres header */ + z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL); + if (!z2->rx_buf) + return -ENOMEM; + + z2->spidev = spi; + init_completion(&z2->boot_irq); + spi_set_drvdata(spi, z2); + + /* Reset the device on boot */ + z2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(z2->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(z2->reset_gpio), "unable to get reset\n"); + + error = devm_request_threaded_irq(dev, z2->spidev->irq, NULL, apple_z2_irq, + IRQF_ONESHOT | IRQF_NO_AUTOEN, + "apple-z2-irq", z2); + if (error) + return dev_err_probe(dev, error, "unable to request irq\n"); + + error = device_property_read_string(dev, "firmware-name", &z2->fw_name); + if (error) + return dev_err_probe(dev, error, "unable to get firmware name\n"); + + z2->input_dev = devm_input_allocate_device(dev); + if (!z2->input_dev) + return -ENOMEM; + + z2->input_dev->name = (char *)spi_get_device_id(spi)->driver_data; + z2->input_dev->phys = "apple_z2"; + z2->input_dev->id.bustype = BUS_SPI; + + /* Allocate the axes before setting from DT */ + input_set_abs_params(z2->input_dev, ABS_MT_POSITION_X, 0, 0, 0, 0); + input_set_abs_params(z2->input_dev, ABS_MT_POSITION_Y, 0, 0, 0, 0); + touchscreen_parse_properties(z2->input_dev, true, &z2->props); + input_abs_set_res(z2->input_dev, ABS_MT_POSITION_X, 100); + input_abs_set_res(z2->input_dev, ABS_MT_POSITION_Y, 100); + input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MAJOR, 0, 65535, 0, 0); + input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MINOR, 0, 65535, 0, 0); + input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MAJOR, 0, 65535, 0, 0); + input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MINOR, 0, 65535, 0, 0); + input_set_abs_params(z2->input_dev, ABS_MT_ORIENTATION, -32768, 32767, 0, 0); + + error = input_mt_init_slots(z2->input_dev, 256, INPUT_MT_DIRECT); + if (error) + return dev_err_probe(dev, error, "unable to initialize multitouch slots\n"); + + error = input_register_device(z2->input_dev); + if (error) + return dev_err_probe(dev, error, "unable to register input device\n"); + + /* Wait for device reset to finish */ + usleep_range(5000, 10000); + error = apple_z2_boot(z2); + if (error) + return error; + + return 0; +} + +static void apple_z2_shutdown(struct spi_device *spi) +{ + struct apple_z2 *z2 = spi_get_drvdata(spi); + + disable_irq(z2->spidev->irq); + gpiod_direction_output(z2->reset_gpio, 1); + z2->booted = false; +} + +static int apple_z2_suspend(struct device *dev) +{ + apple_z2_shutdown(to_spi_device(dev)); + + return 0; +} + +static int apple_z2_resume(struct device *dev) +{ + struct apple_z2 *z2 = spi_get_drvdata(to_spi_device(dev)); + + return apple_z2_boot(z2); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(apple_z2_pm, apple_z2_suspend, apple_z2_resume); + +static const struct of_device_id apple_z2_of_match[] = { + { .compatible = "apple,j293-touchbar" }, + { .compatible = "apple,j493-touchbar" }, + {} +}; +MODULE_DEVICE_TABLE(of, apple_z2_of_match); + +static struct spi_device_id apple_z2_of_id[] = { + { .name = "j293-touchbar", .driver_data = (kernel_ulong_t)"MacBookPro17,1 Touch Bar" }, + { .name = "j493-touchbar", .driver_data = (kernel_ulong_t)"Mac14,7 Touch Bar" }, + {} +}; +MODULE_DEVICE_TABLE(spi, apple_z2_of_id); + +static struct spi_driver apple_z2_driver = { + .driver = { + .name = "apple-z2", + .pm = pm_sleep_ptr(&apple_z2_pm), + .of_match_table = apple_z2_of_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = apple_z2_of_id, + .probe = apple_z2_probe, + .remove = apple_z2_shutdown, +}; + +module_spi_driver(apple_z2_driver); + +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("apple/dfrmtfw-*.bin"); +MODULE_DESCRIPTION("Apple Z2 touchscreens driver"); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 3ddabc5a2c99..f21bf2844112 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -19,6 +19,7 @@ #include <linux/firmware.h> #include <linux/i2c.h> #include <linux/input/mt.h> +#include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/of.h> @@ -274,8 +275,8 @@ struct mxt_cfg { off_t raw_pos; u8 *mem; - size_t mem_size; - int start_ofs; + u16 mem_size; + u16 start_ofs; struct mxt_info info; }; @@ -355,6 +356,8 @@ struct mxt_data { enum mxt_suspend_mode suspend_mode; u32 wakeup_method; + + struct touchscreen_properties prop; }; struct mxt_vb2_buffer { @@ -710,12 +713,11 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len, const void *val) { bool retried = false; - u8 *buf; - size_t count; + size_t count = len + 2; + int error; int ret; - count = len + 2; - buf = kmalloc(count, GFP_KERNEL); + u8 *buf __free(kfree) = kmalloc(count, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -725,20 +727,17 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len, retry: ret = i2c_master_send(client, buf, count); - if (ret == count) { - ret = 0; - } else if (!retried && mxt_wakeup_toggle(client, true, true)) { + if (ret == count) + return 0; + + if (!retried && mxt_wakeup_toggle(client, true, true)) { retried = true; goto retry; - } else { - if (ret >= 0) - ret = -EIO; - dev_err(&client->dev, "%s: i2c send failed (%d)\n", - __func__, ret); } - kfree(buf); - return ret; + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "%s: i2c send failed (%d)\n", __func__, error); + return error; } static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val) @@ -888,8 +887,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) /* Touch active */ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + touchscreen_report_pos(input_dev, &data->prop, x, y, true); input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude); input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area); } else { @@ -1010,8 +1008,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) id, type, x, y, major, pressure, orientation); input_mt_report_slot_state(input_dev, tool, 1); - input_report_abs(input_dev, ABS_MT_POSITION_X, x); - input_report_abs(input_dev, ABS_MT_POSITION_Y, y); + touchscreen_report_pos(input_dev, &data->prop, x, y, true); input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major); input_report_abs(input_dev, ABS_MT_PRESSURE, pressure); input_report_abs(input_dev, ABS_MT_DISTANCE, distance); @@ -1476,7 +1473,7 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg) } cfg->raw_pos += offset; - if (i > mxt_obj_size(object)) + if (i >= mxt_obj_size(object)) continue; byte_offset = reg + i - cfg->start_ofs; @@ -1546,14 +1543,15 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) { struct device *dev = &data->client->dev; struct mxt_cfg cfg; - int ret; + int error; int offset; int i; u32 info_crc, config_crc, calculated_crc; u16 crc_start = 0; /* Make zero terminated copy of the OBP_RAW file */ - cfg.raw = kmemdup_nul(fw->data, fw->size, GFP_KERNEL); + u8 *raw_buf __free(kfree) = cfg.raw = kmemdup_nul(fw->data, fw->size, + GFP_KERNEL); if (!cfg.raw) return -ENOMEM; @@ -1563,21 +1561,17 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) { dev_err(dev, "Unrecognised config file\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } cfg.raw_pos = strlen(MXT_CFG_MAGIC); /* Load information block and check */ for (i = 0; i < sizeof(struct mxt_info); i++) { - ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n", - (unsigned char *)&cfg.info + i, - &offset); - if (ret != 1) { + if (sscanf(cfg.raw + cfg.raw_pos, "%hhx%n", + (unsigned char *)&cfg.info + i, &offset) != 1) { dev_err(dev, "Bad format\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } cfg.raw_pos += offset; @@ -1585,30 +1579,24 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) if (cfg.info.family_id != data->info->family_id) { dev_err(dev, "Family ID mismatch!\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } if (cfg.info.variant_id != data->info->variant_id) { dev_err(dev, "Variant ID mismatch!\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } /* Read CRCs */ - ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset); - if (ret != 1) { + if (sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset) != 1) { dev_err(dev, "Bad format: failed to parse Info CRC\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } cfg.raw_pos += offset; - ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset); - if (ret != 1) { + if (sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset) != 1) { dev_err(dev, "Bad format: failed to parse Config CRC\n"); - ret = -EINVAL; - goto release_raw; + return -EINVAL; } cfg.raw_pos += offset; @@ -1624,8 +1612,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) } else if (config_crc == data->config_crc) { dev_dbg(dev, "Config CRC 0x%06X: OK\n", data->config_crc); - ret = 0; - goto release_raw; + return 0; } else { dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n", data->config_crc, config_crc); @@ -1640,16 +1627,22 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) cfg.start_ofs = MXT_OBJECT_START + data->info->object_num * sizeof(struct mxt_object) + MXT_INFO_CHECKSUM_SIZE; - cfg.mem_size = data->mem_size - cfg.start_ofs; - cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL); - if (!cfg.mem) { - ret = -ENOMEM; - goto release_raw; + + if (data->mem_size <= cfg.start_ofs) { + dev_err(dev, "Memory size too small: %u < %u\n", + data->mem_size, cfg.start_ofs); + return -EINVAL; } - ret = mxt_prepare_cfg_mem(data, &cfg); - if (ret) - goto release_mem; + cfg.mem_size = data->mem_size - cfg.start_ofs; + + u8 *mem_buf __free(kfree) = cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL); + if (!cfg.mem) + return -ENOMEM; + + error = mxt_prepare_cfg_mem(data, &cfg); + if (error) + return error; /* Calculate crc of the received configs (not the raw config file) */ if (data->T71_address) @@ -1669,30 +1662,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw) calculated_crc, config_crc); } - ret = mxt_upload_cfg_mem(data, &cfg); - if (ret) - goto release_mem; + error = mxt_upload_cfg_mem(data, &cfg); + if (error) + return error; mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); - ret = mxt_check_retrigen(data); - if (ret) - goto release_mem; + error = mxt_check_retrigen(data); + if (error) + return error; - ret = mxt_soft_reset(data); - if (ret) - goto release_mem; + error = mxt_soft_reset(data); + if (error) + return error; dev_info(dev, "Config successfully updated\n"); /* T7 config may have changed */ mxt_init_t7_power_cfg(data); -release_mem: - kfree(cfg.mem); -release_raw: - kfree(cfg.raw); - return ret; + return 0; } static void mxt_free_input_device(struct mxt_data *data) @@ -1856,7 +1845,6 @@ static int mxt_read_info_block(struct mxt_data *data) struct i2c_client *client = data->client; int error; size_t size; - void *id_buf, *buf; uint8_t num_objects; u32 calculated_crc; u8 *crc_ptr; @@ -1867,24 +1855,23 @@ static int mxt_read_info_block(struct mxt_data *data) /* Read 7-byte ID information block starting at address 0 */ size = sizeof(struct mxt_info); - id_buf = kzalloc(size, GFP_KERNEL); + void *id_buf __free(kfree) = kzalloc(size, GFP_KERNEL); if (!id_buf) return -ENOMEM; error = __mxt_read_reg(client, 0, size, id_buf); if (error) - goto err_free_mem; + return error; /* Resize buffer to give space for rest of info block */ num_objects = ((struct mxt_info *)id_buf)->object_num; size += (num_objects * sizeof(struct mxt_object)) + MXT_INFO_CHECKSUM_SIZE; - buf = krealloc(id_buf, size, GFP_KERNEL); - if (!buf) { - error = -ENOMEM; - goto err_free_mem; - } + void *buf = krealloc(id_buf, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + id_buf = buf; /* Read rest of info block */ @@ -1892,7 +1879,7 @@ static int mxt_read_info_block(struct mxt_data *data) size - MXT_OBJECT_START, id_buf + MXT_OBJECT_START); if (error) - goto err_free_mem; + return error; /* Extract & calculate checksum */ crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE; @@ -1909,12 +1896,11 @@ static int mxt_read_info_block(struct mxt_data *data) dev_err(&client->dev, "Info Block CRC error calculated=0x%06X read=0x%06X\n", calculated_crc, data->info_crc); - error = -EIO; - goto err_free_mem; + return -EIO; } - data->raw_info_block = id_buf; - data->info = (struct mxt_info *)id_buf; + data->raw_info_block = no_free_ptr(id_buf); + data->info = (struct mxt_info *)data->raw_info_block; dev_info(&client->dev, "Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n", @@ -1923,20 +1909,18 @@ static int mxt_read_info_block(struct mxt_data *data) data->info->build, data->info->object_num); /* Parse object table information */ - error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START); + error = mxt_parse_object_table(data, + data->raw_info_block + MXT_OBJECT_START); if (error) { dev_err(&client->dev, "Error %d parsing object table\n", error); mxt_free_object_table(data); return error; } - data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START); + data->object_table = + (struct mxt_object *)(data->raw_info_block + MXT_OBJECT_START); return 0; - -err_free_mem: - kfree(id_buf); - return error; } static int mxt_read_t9_resolution(struct mxt_data *data) @@ -2212,6 +2196,8 @@ static int mxt_initialize_input_device(struct mxt_data *data) 0, 255, 0, 0); } + touchscreen_parse_properties(input_dev, true, &data->prop); + /* For T15 and T97 Key Array */ if (data->T15_reportid_min || data->T97_reportid_min) { for (i = 0; i < data->t15_num_keys; i++) @@ -2535,8 +2521,6 @@ fault: static const struct vb2_ops mxt_queue_ops = { .queue_setup = mxt_queue_setup, .buf_queue = mxt_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct vb2_queue mxt_queue = { @@ -2913,70 +2897,38 @@ static int mxt_check_firmware_format(struct device *dev, return -EINVAL; } -static int mxt_load_fw(struct device *dev, const char *fn) +static int mxt_flash_fw(struct mxt_data *data, const struct firmware *fw) { - struct mxt_data *data = dev_get_drvdata(dev); - const struct firmware *fw = NULL; + struct device *dev = &data->client->dev; unsigned int frame_size; unsigned int pos = 0; unsigned int retry = 0; unsigned int frame = 0; - int ret; - - ret = request_firmware(&fw, fn, dev); - if (ret) { - dev_err(dev, "Unable to open firmware %s\n", fn); - return ret; - } - - /* Check for incorrect enc file */ - ret = mxt_check_firmware_format(dev, fw); - if (ret) - goto release_firmware; - - if (!data->in_bootloader) { - /* Change to the bootloader mode */ - data->in_bootloader = true; - - ret = mxt_t6_command(data, MXT_COMMAND_RESET, - MXT_BOOT_VALUE, false); - if (ret) - goto release_firmware; - - msleep(MXT_RESET_TIME); - - /* Do not need to scan since we know family ID */ - ret = mxt_lookup_bootloader_address(data, 0); - if (ret) - goto release_firmware; - - mxt_free_input_device(data); - mxt_free_object_table(data); - } else { - enable_irq(data->irq); - } + int error; reinit_completion(&data->bl_completion); - ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); - if (ret) { + error = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); + if (error) { /* Bootloader may still be unlocked from previous attempt */ - ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false); - if (ret) - goto disable_irq; + error = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, + false); + if (error) + return error; } else { dev_info(dev, "Unlocking bootloader\n"); /* Unlock bootloader */ - ret = mxt_send_bootloader_cmd(data, true); - if (ret) - goto disable_irq; + error = mxt_send_bootloader_cmd(data, true); + if (error) + return error; } while (pos < fw->size) { - ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true); - if (ret) - goto disable_irq; + error = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, + true); + if (error) + return error; frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1)); @@ -2984,12 +2936,12 @@ static int mxt_load_fw(struct device *dev, const char *fn) frame_size += 2; /* Write one frame to device */ - ret = mxt_bootloader_write(data, fw->data + pos, frame_size); - if (ret) - goto disable_irq; + error = mxt_bootloader_write(data, fw->data + pos, frame_size); + if (error) + return error; - ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); - if (ret) { + error = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); + if (error) { retry++; /* Back off by 20ms per retry */ @@ -2997,7 +2949,7 @@ static int mxt_load_fw(struct device *dev, const char *fn) if (retry > 20) { dev_err(dev, "Retry count exceeded\n"); - goto disable_irq; + return error; } } else { retry = 0; @@ -3011,10 +2963,10 @@ static int mxt_load_fw(struct device *dev, const char *fn) } /* Wait for flash. */ - ret = mxt_wait_for_completion(data, &data->bl_completion, - MXT_FW_RESET_TIME); - if (ret) - goto disable_irq; + error = mxt_wait_for_completion(data, &data->bl_completion, + MXT_FW_RESET_TIME); + if (error) + return error; dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos); @@ -3024,14 +2976,56 @@ static int mxt_load_fw(struct device *dev, const char *fn) * errors. */ mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME); - data->in_bootloader = false; -disable_irq: + return 0; +} + +static int mxt_load_fw(struct device *dev, const char *fn) +{ + struct mxt_data *data = dev_get_drvdata(dev); + int retval; + int error; + + const struct firmware *fw __free(firmware) = NULL; + error = request_firmware(&fw, fn, dev); + if (error) { + dev_err(dev, "Unable to open firmware %s\n", fn); + return error; + } + + /* Check for incorrect enc file */ + error = mxt_check_firmware_format(dev, fw); + if (error) + return error; + + if (!data->in_bootloader) { + /* Change to the bootloader mode */ + data->in_bootloader = true; + + error = mxt_t6_command(data, MXT_COMMAND_RESET, + MXT_BOOT_VALUE, false); + if (error) + return error; + + msleep(MXT_RESET_TIME); + + /* Do not need to scan since we know family ID */ + error = mxt_lookup_bootloader_address(data, 0); + if (error) + return error; + + mxt_free_input_device(data); + mxt_free_object_table(data); + } else { + enable_irq(data->irq); + } + + retval = mxt_flash_fw(data, fw); + disable_irq(data->irq); -release_firmware: - release_firmware(fw); - return ret; + + return retval; } static ssize_t mxt_update_fw_store(struct device *dev, @@ -3319,7 +3313,7 @@ static int mxt_probe(struct i2c_client *client) if (data->reset_gpio) { /* Wait a while and then de-assert the RESET GPIO line */ msleep(MXT_RESET_GPIO_TIME); - gpiod_set_value(data->reset_gpio, 0); + gpiod_set_value_cansleep(data->reset_gpio, 0); msleep(MXT_RESET_INVALID_CHG); } @@ -3374,12 +3368,10 @@ static int mxt_suspend(struct device *dev) if (!input_dev) return 0; - mutex_lock(&input_dev->mutex); - - if (input_device_enabled(input_dev)) - mxt_stop(data); - - mutex_unlock(&input_dev->mutex); + scoped_guard(mutex, &input_dev->mutex) { + if (input_device_enabled(input_dev)) + mxt_stop(data); + } disable_irq(data->irq); @@ -3397,12 +3389,10 @@ static int mxt_resume(struct device *dev) enable_irq(data->irq); - mutex_lock(&input_dev->mutex); - - if (input_device_enabled(input_dev)) - mxt_start(data); - - mutex_unlock(&input_dev->mutex); + scoped_guard(mutex, &input_dev->mutex) { + if (input_device_enabled(input_dev)) + mxt_start(data); + } return 0; } diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 363a4a1f1560..401b2264f585 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -415,9 +415,9 @@ static int auo_pixcir_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct auo_pixcir_ts *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - int ret = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); /* when configured as wakeup source, device should always wake system * therefore start device if necessary @@ -425,21 +425,23 @@ static int auo_pixcir_suspend(struct device *dev) if (device_may_wakeup(&client->dev)) { /* need to start device if not open, to be wakeup source */ if (!input_device_enabled(input)) { - ret = auo_pixcir_start(ts); - if (ret) - goto unlock; + error = auo_pixcir_start(ts); + if (error) + return error; } enable_irq_wake(client->irq); - ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP); + error = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP); + if (error) + return error; + } else if (input_device_enabled(input)) { - ret = auo_pixcir_stop(ts); + error = auo_pixcir_stop(ts); + if (error) + return error; } -unlock: - mutex_unlock(&input->mutex); - - return ret; + return 0; } static int auo_pixcir_resume(struct device *dev) @@ -447,29 +449,28 @@ static int auo_pixcir_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct auo_pixcir_ts *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - int ret = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (device_may_wakeup(&client->dev)) { disable_irq_wake(client->irq); /* need to stop device if it was not open on suspend */ if (!input_device_enabled(input)) { - ret = auo_pixcir_stop(ts); - if (ret) - goto unlock; + error = auo_pixcir_stop(ts); + if (error) + return error; } /* device wakes automatically from SLEEP */ } else if (input_device_enabled(input)) { - ret = auo_pixcir_start(ts); + error = auo_pixcir_start(ts); + if (error) + return error; } -unlock: - mutex_unlock(&input->mutex); - - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops, diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 686d0a6b1570..68d9cd55ceeb 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -209,7 +209,8 @@ static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf) static void bu21029_touch_release(struct timer_list *t) { - struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer); + struct bu21029_ts_data *bu21029 = timer_container_of(bu21029, t, + timer); input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0); input_report_key(bu21029->in_dev, BTN_TOUCH, 0); @@ -325,7 +326,7 @@ static void bu21029_stop_chip(struct input_dev *dev) struct bu21029_ts_data *bu21029 = input_get_drvdata(dev); disable_irq(bu21029->client->irq); - del_timer_sync(&bu21029->timer); + timer_delete_sync(&bu21029->timer); bu21029_put_chip_in_reset(bu21029); regulator_disable(bu21029->vdd); @@ -415,10 +416,10 @@ static int bu21029_suspend(struct device *dev) struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c); if (!device_may_wakeup(dev)) { - mutex_lock(&bu21029->in_dev->mutex); + guard(mutex)(&bu21029->in_dev->mutex); + if (input_device_enabled(bu21029->in_dev)) bu21029_stop_chip(bu21029->in_dev); - mutex_unlock(&bu21029->in_dev->mutex); } return 0; @@ -430,10 +431,10 @@ static int bu21029_resume(struct device *dev) struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c); if (!device_may_wakeup(dev)) { - mutex_lock(&bu21029->in_dev->mutex); + guard(mutex)(&bu21029->in_dev->mutex); + if (input_device_enabled(bu21029->in_dev)) bu21029_start_chip(bu21029->in_dev); - mutex_unlock(&bu21029->in_dev->mutex); } return 0; diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index d6876d10b252..1b10a757313c 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -152,10 +152,10 @@ static int icn8318_suspend(struct device *dev) { struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->input->mutex); + guard(mutex)(&data->input->mutex); + if (input_device_enabled(data->input)) icn8318_stop(data->input); - mutex_unlock(&data->input->mutex); return 0; } @@ -164,10 +164,10 @@ static int icn8318_resume(struct device *dev) { struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->input->mutex); + guard(mutex)(&data->input->mutex); + if (input_device_enabled(data->input)) icn8318_start(data->input); - mutex_unlock(&data->input->mutex); return 0; } diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index eafe5a9b8964..47f4271395a6 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -580,7 +580,7 @@ static int cyttsp5_power_control(struct cyttsp5 *ts, bool on) int rc; SET_CMD_REPORT_TYPE(cmd[0], 0); - SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP); + SET_CMD_REPORT_ID(cmd[0], state); SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER); rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd)); @@ -870,13 +870,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq, ts->input->phys = ts->phys; input_set_drvdata(ts->input, ts); - /* Reset the gpio to be in a reset state */ + /* Assert gpio to be in a reset state */ ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->reset_gpio)) { error = PTR_ERR(ts->reset_gpio); dev_err(dev, "Failed to request reset gpio, error %d\n", error); return error; } + + fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */ + gpiod_set_value_cansleep(ts->reset_gpio, 0); /* Need a delay to have device up */ @@ -920,8 +923,8 @@ static int cyttsp5_i2c_probe(struct i2c_client *client) regmap = devm_regmap_init_i2c(client, &config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "regmap allocation failed: %ld\n", - PTR_ERR(regmap)); + dev_err(&client->dev, "regmap allocation failed: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c index b8ce6012364c..012dfcae01cc 100644 --- a/drivers/input/touchscreen/cyttsp_core.c +++ b/drivers/input/touchscreen/cyttsp_core.c @@ -14,6 +14,7 @@ */ #include <linux/delay.h> +#include <linux/export.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> @@ -493,34 +494,30 @@ static int cyttsp_disable(struct cyttsp *ts) static int cyttsp_suspend(struct device *dev) { struct cyttsp *ts = dev_get_drvdata(dev); - int retval = 0; + int error; - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); if (input_device_enabled(ts->input)) { - retval = cyttsp_disable(ts); - if (retval == 0) - ts->suspended = true; + error = cyttsp_disable(ts); + if (error) + return error; } - mutex_unlock(&ts->input->mutex); - - return retval; + ts->suspended = true; + return 0; } static int cyttsp_resume(struct device *dev) { struct cyttsp *ts = dev_get_drvdata(dev); - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); if (input_device_enabled(ts->input)) cyttsp_enable(ts); ts->suspended = false; - - mutex_unlock(&ts->input->mutex); - return 0; } diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c index c2d3252f8466..a8e3d85eece7 100644 --- a/drivers/input/touchscreen/da9052_tsi.c +++ b/drivers/input/touchscreen/da9052_tsi.c @@ -232,7 +232,7 @@ static int da9052_ts_probe(struct platform_device *pdev) if (!da9052) return -EINVAL; - tsi = kzalloc(sizeof(*tsi), GFP_KERNEL); + tsi = kzalloc_obj(*tsi); input_dev = input_allocate_device(); if (!tsi || !input_dev) { error = -ENOMEM; diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c index fe626a226b85..943ba8c2fb6c 100644 --- a/drivers/input/touchscreen/dynapro.c +++ b/drivers/input/touchscreen/dynapro.c @@ -110,7 +110,7 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - pdynapro = kzalloc(sizeof(*pdynapro), GFP_KERNEL); + pdynapro = kzalloc_obj(*pdynapro); input_dev = input_allocate_device(); if (!pdynapro || !input_dev) { err = -ENOMEM; @@ -119,8 +119,8 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv) pdynapro->serio = serio; pdynapro->dev = input_dev; - snprintf(pdynapro->phys, sizeof(pdynapro->phys), - "%s/input0", serio->phys); + scnprintf(pdynapro->phys, sizeof(pdynapro->phys), + "%s/input0", serio->phys); input_dev->name = "Dynapro Serial TouchScreen"; input_dev->phys = pdynapro->phys; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 0d7bf18e2508..d3b1177185a3 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -120,7 +120,6 @@ struct edt_ft5x06_ts_data { struct regmap *regmap; #if defined(CONFIG_DEBUG_FS) - struct dentry *debug_dir; u8 *raw_buffer; size_t raw_bufsize; #endif @@ -381,16 +380,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, container_of(dattr, struct edt_ft5x06_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; unsigned int val; - size_t count = 0; - int error = 0; + int error; u8 addr; - mutex_lock(&tsdata->mutex); + guard(mutex)(&tsdata->mutex); - if (tsdata->factory_mode) { - error = -EIO; - goto out; - } + if (tsdata->factory_mode) + return -EIO; switch (tsdata->version) { case EDT_M06: @@ -408,8 +404,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, break; default: - error = -ENODEV; - goto out; + return -ENODEV; } if (addr != NO_REGISTER) { @@ -418,7 +413,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, dev_err(&tsdata->client->dev, "Failed to fetch attribute %s, error %d\n", dattr->attr.name, error); - goto out; + return error; } } else { val = *field; @@ -431,10 +426,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, *field = val; } - count = sysfs_emit(buf, "%d\n", val); -out: - mutex_unlock(&tsdata->mutex); - return error ?: count; + return sysfs_emit(buf, "%d\n", val); } static ssize_t edt_ft5x06_setting_store(struct device *dev, @@ -450,21 +442,17 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, int error; u8 addr; - mutex_lock(&tsdata->mutex); + guard(mutex)(&tsdata->mutex); - if (tsdata->factory_mode) { - error = -EIO; - goto out; - } + if (tsdata->factory_mode) + return -EIO; error = kstrtouint(buf, 0, &val); if (error) - goto out; + return error; - if (val < attr->limit_low || val > attr->limit_high) { - error = -ERANGE; - goto out; - } + if (val < attr->limit_low || val > attr->limit_high) + return -ERANGE; switch (tsdata->version) { case EDT_M06: @@ -482,8 +470,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, break; default: - error = -ENODEV; - goto out; + return -ENODEV; } if (addr != NO_REGISTER) { @@ -492,14 +479,12 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, dev_err(&tsdata->client->dev, "Failed to update attribute %s, error: %d\n", dattr->attr.name, error); - goto out; + return error; } } *field = val; -out: - mutex_unlock(&tsdata->mutex); - return error ?: count; + return count; } /* m06, m09: range 0-31, m12: range 0-5 */ @@ -715,21 +700,17 @@ static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode) static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode) { struct edt_ft5x06_ts_data *tsdata = data; - int retval = 0; if (mode > 1) return -ERANGE; - mutex_lock(&tsdata->mutex); - - if (mode != tsdata->factory_mode) { - retval = mode ? edt_ft5x06_factory_mode(tsdata) : - edt_ft5x06_work_mode(tsdata); - } + guard(mutex)(&tsdata->mutex); - mutex_unlock(&tsdata->mutex); + if (mode == tsdata->factory_mode) + return 0; - return retval; + return mode ? edt_ft5x06_factory_mode(tsdata) : + edt_ft5x06_work_mode(tsdata); }; DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, @@ -751,18 +732,16 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, if (*off < 0 || *off >= tsdata->raw_bufsize) return 0; - mutex_lock(&tsdata->mutex); + guard(mutex)(&tsdata->mutex); - if (!tsdata->factory_mode || !tsdata->raw_buffer) { - error = -EIO; - goto out; - } + if (!tsdata->factory_mode || !tsdata->raw_buffer) + return -EIO; error = regmap_write(tsdata->regmap, 0x08, 0x01); if (error) { dev_err(&client->dev, "failed to write 0x08 register, error %d\n", error); - goto out; + return error; } do { @@ -772,7 +751,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, dev_err(&client->dev, "failed to read 0x08 register, error %d\n", error); - goto out; + return error; } if (val == 1) @@ -782,8 +761,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, if (retries == 0) { dev_err(&client->dev, "timed out waiting for register to settle\n"); - error = -ETIMEDOUT; - goto out; + return -ETIMEDOUT; } rdbuf = tsdata->raw_buffer; @@ -793,21 +771,17 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, rdbuf[0] = i; /* column index */ error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes); if (error) - goto out; + return error; rdbuf += colbytes; } read = min_t(size_t, count, tsdata->raw_bufsize - *off); - if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) { - error = -EFAULT; - goto out; - } + if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) + return -EFAULT; *off += read; -out: - mutex_unlock(&tsdata->mutex); - return error ?: read; + return read; }; static const struct file_operations debugfs_raw_data_fops = { @@ -815,24 +789,25 @@ static const struct file_operations debugfs_raw_data_fops = { .read = edt_ft5x06_debugfs_raw_data_read, }; -static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, - const char *debugfs_name) +static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata) { - tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL); + struct dentry *debug_dir = tsdata->client->debugfs; - debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x); - debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y); + debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x); + debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y); debugfs_create_file("mode", S_IRUSR | S_IWUSR, - tsdata->debug_dir, tsdata, &debugfs_mode_fops); + debug_dir, tsdata, &debugfs_mode_fops); debugfs_create_file("raw_data", S_IRUSR, - tsdata->debug_dir, tsdata, &debugfs_raw_data_fops); + debug_dir, tsdata, &debugfs_raw_data_fops); } static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) { - debugfs_remove_recursive(tsdata->debug_dir); + guard(mutex)(&tsdata->mutex); + kfree(tsdata->raw_buffer); + tsdata->raw_buffer = NULL; } #else @@ -842,8 +817,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) return -ENOSYS; } -static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata, - const char *debugfs_name) +static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata) { } @@ -1349,7 +1323,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) if (error) return error; - edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev)); + edt_ft5x06_ts_prepare_debugfs(tsdata); dev_dbg(&client->dev, "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", @@ -1479,6 +1453,10 @@ static const struct edt_i2c_chip_data edt_ft5x06_data = { .max_support_points = 5, }; +static const struct edt_i2c_chip_data edt_ft3518_data = { + .max_support_points = 10, +}; + static const struct edt_i2c_chip_data edt_ft5452_data = { .max_support_points = 5, }; @@ -1495,6 +1473,10 @@ static const struct edt_i2c_chip_data edt_ft8201_data = { .max_support_points = 10, }; +static const struct edt_i2c_chip_data edt_ft8716_data = { + .max_support_points = 10, +}; + static const struct edt_i2c_chip_data edt_ft8719_data = { .max_support_points = 10, }; @@ -1503,10 +1485,12 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = { { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data }, { .name = "ev-ft5726", .driver_data = (long)&edt_ft5506_data }, + { .name = "ft3518", .driver_data = (long)&edt_ft3518_data }, { .name = "ft5452", .driver_data = (long)&edt_ft5452_data }, /* Note no edt- prefix for compatibility with the ft6236.c driver */ { .name = "ft6236", .driver_data = (long)&edt_ft6236_data }, { .name = "ft8201", .driver_data = (long)&edt_ft8201_data }, + { .name = "ft8716", .driver_data = (long)&edt_ft8716_data }, { .name = "ft8719", .driver_data = (long)&edt_ft8719_data }, { /* sentinel */ } }; @@ -1518,11 +1502,13 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data }, { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, { .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data }, + { .compatible = "focaltech,ft3518", .data = &edt_ft3518_data }, { .compatible = "focaltech,ft5426", .data = &edt_ft5506_data }, { .compatible = "focaltech,ft5452", .data = &edt_ft5452_data }, /* Note focaltech vendor prefix for compatibility with ft6236.c */ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, { .compatible = "focaltech,ft8201", .data = &edt_ft8201_data }, + { .compatible = "focaltech,ft8716", .data = &edt_ft8716_data }, { .compatible = "focaltech,ft8719", .data = &edt_ft8719_data }, { /* sentinel */ } }; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 87eb18977b71..492e19a28a74 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -89,7 +89,7 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id) struct eeti_ts *eeti = dev_id; int error; - mutex_lock(&eeti->mutex); + guard(mutex)(&eeti->mutex); do { /* @@ -109,13 +109,12 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id) } while (eeti->running && eeti->attn_gpio); - mutex_unlock(&eeti->mutex); return IRQ_HANDLED; } static void eeti_ts_start(struct eeti_ts *eeti) { - mutex_lock(&eeti->mutex); + guard(mutex)(&eeti->mutex); eeti->running = true; enable_irq(eeti->client->irq); @@ -127,8 +126,6 @@ static void eeti_ts_start(struct eeti_ts *eeti) */ if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)) eeti_ts_read(eeti); - - mutex_unlock(&eeti->mutex); } static void eeti_ts_stop(struct eeti_ts *eeti) @@ -238,12 +235,10 @@ static int eeti_ts_suspend(struct device *dev) struct eeti_ts *eeti = i2c_get_clientdata(client); struct input_dev *input_dev = eeti->input; - mutex_lock(&input_dev->mutex); - - if (input_device_enabled(input_dev)) - eeti_ts_stop(eeti); - - mutex_unlock(&input_dev->mutex); + scoped_guard(mutex, &input_dev->mutex) { + if (input_device_enabled(input_dev)) + eeti_ts_stop(eeti); + } if (device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); @@ -260,12 +255,10 @@ static int eeti_ts_resume(struct device *dev) if (device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); - mutex_lock(&input_dev->mutex); - - if (input_device_enabled(input_dev)) - eeti_ts_start(eeti); - - mutex_unlock(&input_dev->mutex); + scoped_guard(mutex, &input_dev->mutex) { + if (input_device_enabled(input_dev)) + eeti_ts_start(eeti); + } return 0; } diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c index 07a4aa1c19bb..e04ea1fea4ad 100644 --- a/drivers/input/touchscreen/egalax_ts_serial.c +++ b/drivers/input/touchscreen/egalax_ts_serial.c @@ -99,7 +99,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int error; - egalax = kzalloc(sizeof(*egalax), GFP_KERNEL); + egalax = kzalloc_obj(*egalax); input_dev = input_allocate_device(); if (!egalax || !input_dev) { error = -ENOMEM; @@ -108,8 +108,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv) egalax->serio = serio; egalax->input = input_dev; - snprintf(egalax->phys, sizeof(egalax->phys), - "%s/input0", serio->phys); + scnprintf(egalax->phys, sizeof(egalax->phys), "%s/input0", serio->phys); input_dev->name = "EETI eGalaxTouch Serial TouchScreen"; input_dev->phys = egalax->phys; diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index 46a0611fac82..572a37d4e0aa 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -187,10 +187,10 @@ static int ektf2127_suspend(struct device *dev) { struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); + if (input_device_enabled(ts->input)) ektf2127_stop(ts->input); - mutex_unlock(&ts->input->mutex); return 0; } @@ -199,10 +199,10 @@ static int ektf2127_resume(struct device *dev) { struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); + if (input_device_enabled(ts->input)) ektf2127_start(ts->input); - mutex_unlock(&ts->input->mutex); return 0; } diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 3fd170f75b4a..835d91dff0a4 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -303,15 +303,13 @@ static int elants_i2c_calibrate(struct elants_data *ts) static const u8 rek[] = { CMD_HEADER_WRITE, 0x29, 0x00, 0x01 }; static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; - disable_irq(client->irq); - - ts->state = ELAN_WAIT_RECALIBRATION; - reinit_completion(&ts->cmd_done); - - elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); - elants_i2c_send(client, rek, sizeof(rek)); + scoped_guard(disable_irq, &client->irq) { + ts->state = ELAN_WAIT_RECALIBRATION; + reinit_completion(&ts->cmd_done); - enable_irq(client->irq); + elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); + elants_i2c_send(client, rek, sizeof(rek)); + } ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); @@ -906,17 +904,17 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client, static int elants_i2c_fw_update(struct elants_data *ts) { struct i2c_client *client = ts->client; - const struct firmware *fw; - char *fw_name; int error; - fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); + const char *fw_name __free(kfree) = + kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); if (!fw_name) return -ENOMEM; dev_info(&client->dev, "requesting fw name = %s\n", fw_name); + + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_name, &client->dev); - kfree(fw_name); if (error) { dev_err(&client->dev, "failed to request firmware: %d\n", error); @@ -926,40 +924,32 @@ static int elants_i2c_fw_update(struct elants_data *ts) if (fw->size % ELAN_FW_PAGESIZE) { dev_err(&client->dev, "invalid firmware length: %zu\n", fw->size); - error = -EINVAL; - goto out; + return -EINVAL; } - disable_irq(client->irq); + scoped_guard(disable_irq, &client->irq) { + bool force_update = ts->iap_mode == ELAN_IAP_RECOVERY; - error = elants_i2c_do_update_firmware(client, fw, - ts->iap_mode == ELAN_IAP_RECOVERY); - if (error) { - dev_err(&client->dev, "firmware update failed: %d\n", error); - ts->iap_mode = ELAN_IAP_RECOVERY; - goto out_enable_irq; - } + error = elants_i2c_do_update_firmware(client, fw, force_update); + if (error) { + dev_err(&client->dev, "firmware update failed: %d\n", + error); + } else { + error = elants_i2c_initialize(ts); + if (error) + dev_err(&client->dev, + "failed to initialize device after firmware update: %d\n", + error); + } - error = elants_i2c_initialize(ts); - if (error) { - dev_err(&client->dev, - "failed to initialize device after firmware update: %d\n", - error); - ts->iap_mode = ELAN_IAP_RECOVERY; - goto out_enable_irq; + ts->iap_mode = error ? ELAN_IAP_RECOVERY : ELAN_IAP_OPERATIONAL; + ts->state = ELAN_STATE_NORMAL; } - - ts->iap_mode = ELAN_IAP_OPERATIONAL; - -out_enable_irq: - ts->state = ELAN_STATE_NORMAL; - enable_irq(client->irq); msleep(100); if (!error) elants_i2c_calibrate(ts); -out: - release_firmware(fw); + return error; } @@ -1186,14 +1176,13 @@ static ssize_t calibrate_store(struct device *dev, struct elants_data *ts = i2c_get_clientdata(client); int error; - error = mutex_lock_interruptible(&ts->sysfs_mutex); - if (error) - return error; - - error = elants_i2c_calibrate(ts); + scoped_cond_guard(mutex_intr, return -EINTR, &ts->sysfs_mutex) { + error = elants_i2c_calibrate(ts); + if (error) + return error; + } - mutex_unlock(&ts->sysfs_mutex); - return error ?: count; + return count; } static ssize_t write_update_fw(struct device *dev, @@ -1204,15 +1193,13 @@ static ssize_t write_update_fw(struct device *dev, struct elants_data *ts = i2c_get_clientdata(client); int error; - error = mutex_lock_interruptible(&ts->sysfs_mutex); - if (error) - return error; - - error = elants_i2c_fw_update(ts); - dev_dbg(dev, "firmware update result: %d\n", error); + scoped_cond_guard(mutex_intr, return -EINTR, &ts->sysfs_mutex) { + error = elants_i2c_fw_update(ts); + if (error) + return error; + } - mutex_unlock(&ts->sysfs_mutex); - return error ?: count; + return count; } static ssize_t show_iap_mode(struct device *dev, diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c index ad209e6e82a6..6814d5789b6f 100644 --- a/drivers/input/touchscreen/elo.c +++ b/drivers/input/touchscreen/elo.c @@ -219,40 +219,40 @@ static irqreturn_t elo_interrupt(struct serio *serio, static int elo_command_10(struct elo *elo, unsigned char *packet) { - int rc = -1; + int error; int i; unsigned char csum = 0xaa + ELO10_LEAD_BYTE; - mutex_lock(&elo->cmd_mutex); + guard(mutex)(&elo->cmd_mutex); scoped_guard(serio_pause_rx, elo->serio) { elo->expected_packet = toupper(packet[0]); init_completion(&elo->cmd_done); } - if (serio_write(elo->serio, ELO10_LEAD_BYTE)) - goto out; + error = serio_write(elo->serio, ELO10_LEAD_BYTE); + if (error) + return error; for (i = 0; i < ELO10_PACKET_LEN; i++) { csum += packet[i]; - if (serio_write(elo->serio, packet[i])) - goto out; + error = serio_write(elo->serio, packet[i]); + if (error) + return error; } - if (serio_write(elo->serio, csum)) - goto out; + error = serio_write(elo->serio, csum); + if (error) + return error; wait_for_completion_timeout(&elo->cmd_done, HZ); - if (elo->expected_packet == ELO10_TOUCH_PACKET) { - /* We are back in reporting mode, the command was ACKed */ - memcpy(packet, elo->response, ELO10_PACKET_LEN); - rc = 0; - } + if (elo->expected_packet != ELO10_TOUCH_PACKET) + return -EIO; - out: - mutex_unlock(&elo->cmd_mutex); - return rc; + /* We are back in reporting mode, the command was ACKed */ + memcpy(packet, elo->response, ELO10_PACKET_LEN); + return 0; } static int elo_setup_10(struct elo *elo) @@ -307,7 +307,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - elo = kzalloc(sizeof(*elo), GFP_KERNEL); + elo = kzalloc_obj(*elo); input_dev = input_allocate_device(); if (!elo || !input_dev) { err = -ENOMEM; @@ -320,7 +320,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) elo->expected_packet = ELO10_TOUCH_PACKET; mutex_init(&elo->cmd_mutex); init_completion(&elo->cmd_done); - snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); + scnprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys); input_dev->name = "Elo Serial TouchScreen"; input_dev->phys = elo->phys; diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index fdda8412b164..78c0911ba6e2 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -105,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input, static void exc3000_timer(struct timer_list *t) { - struct exc3000_data *data = from_timer(data, t, timer); + struct exc3000_data *data = timer_container_of(data, t, timer); input_mt_sync_frame(data->input); input_sync(data->input); @@ -174,7 +174,7 @@ static int exc3000_handle_mt_event(struct exc3000_data *data) /* * We read full state successfully, no contacts will be "stuck". */ - del_timer_sync(&data->timer); + timer_delete_sync(&data->timer); while (total_slots > 0) { int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); @@ -234,7 +234,7 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, int ret; unsigned long time_left; - mutex_lock(&data->query_lock); + guard(mutex)(&data->query_lock); reinit_completion(&data->wait_event); @@ -243,29 +243,18 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request, ret = i2c_master_send(data->client, buf, EXC3000_LEN_VENDOR_REQUEST); if (ret < 0) - goto out_unlock; - - if (response) { - time_left = wait_for_completion_timeout(&data->wait_event, - timeout * HZ); - if (time_left == 0) { - ret = -ETIMEDOUT; - goto out_unlock; - } - - if (data->buf[3] >= EXC3000_LEN_FRAME) { - ret = -ENOSPC; - goto out_unlock; - } + return ret; - memcpy(response, &data->buf[4], data->buf[3]); - ret = data->buf[3]; - } + time_left = wait_for_completion_timeout(&data->wait_event, + timeout * HZ); + if (time_left == 0) + return -ETIMEDOUT; -out_unlock: - mutex_unlock(&data->query_lock); + if (data->buf[3] >= EXC3000_LEN_FRAME) + return -ENOSPC; - return ret; + memcpy(response, &data->buf[4], data->buf[3]); + return data->buf[3]; } static ssize_t fw_version_show(struct device *dev, diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c index a32708652d10..ff270b3b8572 100644 --- a/drivers/input/touchscreen/fsl-imx25-tcq.c +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c @@ -39,7 +39,6 @@ struct mx25_tcq_priv { }; static const struct regmap_config mx25_tcq_regconfig = { - .fast_io = true, .max_register = 0x5c, .reg_bits = 32, .val_bits = 32, diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c index 1a3e14ea2e08..8ed592294b17 100644 --- a/drivers/input/touchscreen/fujitsu_ts.c +++ b/drivers/input/touchscreen/fujitsu_ts.c @@ -99,7 +99,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - fujitsu = kzalloc(sizeof(*fujitsu), GFP_KERNEL); + fujitsu = kzalloc_obj(*fujitsu); input_dev = input_allocate_device(); if (!fujitsu || !input_dev) { err = -ENOMEM; @@ -108,8 +108,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv) fujitsu->serio = serio; fujitsu->dev = input_dev; - snprintf(fujitsu->phys, sizeof(fujitsu->phys), - "%s/input0", serio->phys); + scnprintf(fujitsu->phys, sizeof(fujitsu->phys), "%s/input0", serio->phys); input_dev->name = "Fujitsu Serial Touchscreen"; input_dev->phys = fujitsu->phys; diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index a3e8a51c9144..f8798d11ec03 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -44,9 +44,11 @@ #define GOODIX_HAVE_KEY BIT(4) #define GOODIX_BUFFER_STATUS_TIMEOUT 20 -#define RESOLUTION_LOC 1 -#define MAX_CONTACTS_LOC 5 -#define TRIGGER_LOC 6 +#define RESOLUTION_LOC 1 +#define MAX_CONTACTS_LOC 5 +#define TRIGGER_LOC 6 + +#define GOODIX_POLL_INTERVAL_MS 17 /* 17ms = 60fps */ /* Our special handling for GPIO accesses through ACPI is x86 specific */ #if defined CONFIG_X86 && defined CONFIG_ACPI @@ -497,6 +499,14 @@ sync: input_sync(ts->input_dev); } +static void goodix_ts_work_i2c_poll(struct input_dev *input) +{ + struct goodix_ts_data *ts = input_get_drvdata(input); + + goodix_process_events(ts); + goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0); +} + /** * goodix_ts_irq_handler - The IRQ handler * @@ -513,13 +523,29 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static void goodix_enable_irq(struct goodix_ts_data *ts) +{ + if (ts->client->irq) + enable_irq(ts->client->irq); +} + +static void goodix_disable_irq(struct goodix_ts_data *ts) +{ + if (ts->client->irq) + disable_irq(ts->client->irq); +} + static void goodix_free_irq(struct goodix_ts_data *ts) { - devm_free_irq(&ts->client->dev, ts->client->irq, ts); + if (ts->client->irq) + devm_free_irq(&ts->client->dev, ts->client->irq, ts); } static int goodix_request_irq(struct goodix_ts_data *ts) { + if (!ts->client->irq) + return 0; + return devm_request_threaded_irq(&ts->client->dev, ts->client->irq, NULL, goodix_ts_irq_handler, ts->irq_flags, ts->client->name, ts); @@ -770,17 +796,6 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts) usleep_range(6000, 10000); /* T4: > 5ms */ - /* - * Put the reset pin back in to input / high-impedance mode to save - * power. Only do this in the non ACPI case since some ACPI boards - * don't have a pull-up, so there the reset pin must stay active-high. - */ - if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) { - error = gpiod_direction_input(ts->gpiod_rst); - if (error) - goto error; - } - return 0; error: @@ -931,14 +946,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) return -EINVAL; } - /* - * Normally we put the reset pin in input / high-impedance mode to save - * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI - * case, leave the pin as is. This results in the pin not being touched - * at all on x86/ACPI boards, except when needed for error-recover. - */ - ts->gpiod_rst_flags = GPIOD_ASIS; - return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping); } #else @@ -963,12 +970,6 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts) return -EINVAL; dev = &ts->client->dev; - /* - * By default we request the reset pin as input, leaving it in - * high-impedance when not resetting the controller to save power. - */ - ts->gpiod_rst_flags = GPIOD_IN; - ts->avdd28 = devm_regulator_get(dev, "AVDD28"); if (IS_ERR(ts->avdd28)) return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n"); @@ -993,7 +994,7 @@ retry_get_irq_gpio: ts->gpiod_int = gpiod; /* Get the reset line GPIO pin number */ - gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags); + gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_ASIS); if (IS_ERR(gpiod)) return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", GOODIX_GPIO_RST_NAME); @@ -1219,6 +1220,18 @@ retry_read_config: return error; } + input_set_drvdata(ts->input_dev, ts); + + if (!ts->client->irq) { + error = input_setup_polling(ts->input_dev, goodix_ts_work_i2c_poll); + if (error) { + dev_err(&ts->client->dev, + "could not set up polling mode, %d\n", error); + return error; + } + input_set_poll_interval(ts->input_dev, GOODIX_POLL_INTERVAL_MS); + } + error = input_register_device(ts->input_dev); if (error) { dev_err(&ts->client->dev, @@ -1422,7 +1435,7 @@ static int goodix_suspend(struct device *dev) /* We need gpio pins to suspend/resume */ if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { - disable_irq(client->irq); + goodix_disable_irq(ts); return 0; } @@ -1466,7 +1479,7 @@ static int goodix_resume(struct device *dev) int error; if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) { - enable_irq(client->irq); + goodix_enable_irq(ts); return 0; } @@ -1519,6 +1532,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, { "GDIX1002", 0 }, + { "GDIX1003", 0 }, { "GDX9110", 0 }, { } }; diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index 87797cc88b32..0d1e8a8d2cba 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -88,7 +88,6 @@ struct goodix_ts_data { struct gpio_desc *gpiod_rst; int gpio_count; int gpio_int_idx; - enum gpiod_flags gpiod_rst_flags; char id[GOODIX_ID_MAX_LEN + 1]; char cfg_name[64]; u16 version; diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h index 38b6f9ddbdef..d8bbd4853206 100644 --- a/drivers/input/touchscreen/goodix_berlin.h +++ b/drivers/input/touchscreen/goodix_berlin.h @@ -12,12 +12,26 @@ #include <linux/pm.h> +#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A 0x1000C +#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D 0x10014 + +#define GOODIX_BERLIN_IC_INFO_ADDR_A 0x10068 +#define GOODIX_BERLIN_IC_INFO_ADDR_D 0x10070 + +struct goodix_berlin_ic_data { + int fw_version_info_addr; + int ic_info_addr; + ssize_t read_dummy_len; + ssize_t read_prefix_len; +}; + struct device; struct input_id; struct regmap; int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, - struct regmap *regmap); + struct regmap *regmap, + const struct goodix_berlin_ic_data *ic_data); extern const struct dev_pm_ops goodix_berlin_pm_ops; extern const struct attribute_group *goodix_berlin_groups[]; diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c index 7f8cfdd106fa..b0938a4f3fec 100644 --- a/drivers/input/touchscreen/goodix_berlin_core.c +++ b/drivers/input/touchscreen/goodix_berlin_core.c @@ -12,7 +12,7 @@ * to the previous generations. * * Currently the driver only handles Multitouch events with already - * programmed firmware and "config" for "Revision D" Berlin IC. + * programmed firmware and "config" for "Revision A/D" Berlin IC. * * Support is missing for: * - ESD Management @@ -20,14 +20,16 @@ * - "Config" update/flashing * - Stylus Events * - Gesture Events - * - Support for older revisions (A & B) + * - Support for revision B */ #include <linux/bitfield.h> +#include <linux/export.h> #include <linux/gpio/consumer.h> #include <linux/input.h> #include <linux/input/mt.h> #include <linux/input/touchscreen.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/sizes.h> @@ -53,10 +55,8 @@ #define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA #define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000 -#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR 0x10014 #define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K -#define GOODIX_BERLIN_IC_INFO_ADDR 0x10070 #define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16) @@ -175,6 +175,8 @@ struct goodix_berlin_core { /* Runtime parameters extracted from IC_INFO buffer */ u32 touch_data_addr; + const struct goodix_berlin_ic_data *ic_data; + struct goodix_berlin_event event; }; @@ -299,7 +301,7 @@ static int goodix_berlin_read_version(struct goodix_berlin_core *cd) { int error; - error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_FW_VERSION_INFO_ADDR, + error = regmap_raw_read(cd->regmap, cd->ic_data->fw_version_info_addr, &cd->fw_version, sizeof(cd->fw_version)); if (error) { dev_err(cd->dev, "error reading fw version, %d\n", error); @@ -367,7 +369,7 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd) if (!afe_data) return -ENOMEM; - error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR, + error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, &length_raw, sizeof(length_raw)); if (error) { dev_err(cd->dev, "failed get ic info length, %d\n", error); @@ -380,8 +382,8 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd) return -EINVAL; } - error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR, - afe_data, length); + error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, afe_data, + length); if (error) { dev_err(cd->dev, "failed get ic info data, %d\n", error); return error; @@ -626,6 +628,14 @@ static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd, touchscreen_parse_properties(cd->input_dev, true, &cd->props); + /* + * The resolution of these touchscreens is about 10 units/mm, the actual + * resolution does not matter much since we set INPUT_PROP_DIRECT. + * Set it to 10 to ensure userspace isn't off by an order of magnitude. + */ + input_abs_set_res(cd->input_dev, ABS_MT_POSITION_X, 10); + input_abs_set_res(cd->input_dev, ABS_MT_POSITION_Y, 10); + error = input_mt_init_slots(cd->input_dev, GOODIX_BERLIN_MAX_TOUCH, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) @@ -673,7 +683,7 @@ static void goodix_berlin_power_off_act(void *data) } static ssize_t registers_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); @@ -686,7 +696,7 @@ static ssize_t registers_read(struct file *filp, struct kobject *kobj, } static ssize_t registers_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, + const struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); @@ -698,9 +708,9 @@ static ssize_t registers_write(struct file *filp, struct kobject *kobj, return error ? error : count; } -static BIN_ATTR_ADMIN_RW(registers, 0); +static const BIN_ATTR_ADMIN_RW(registers, 0); -static struct bin_attribute *goodix_berlin_bin_attrs[] = { +static const struct bin_attribute *const goodix_berlin_bin_attrs[] = { &bin_attr_registers, NULL, }; @@ -716,7 +726,8 @@ const struct attribute_group *goodix_berlin_groups[] = { EXPORT_SYMBOL_GPL(goodix_berlin_groups); int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, - struct regmap *regmap) + struct regmap *regmap, + const struct goodix_berlin_ic_data *ic_data) { struct goodix_berlin_core *cd; int error; @@ -733,6 +744,7 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, cd->dev = dev; cd->regmap = regmap; cd->irq = irq; + cd->ic_data = ic_data; cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(cd->reset_gpio)) diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c index ad7a60d94338..929090a094bf 100644 --- a/drivers/input/touchscreen/goodix_berlin_i2c.c +++ b/drivers/input/touchscreen/goodix_berlin_i2c.c @@ -31,6 +31,8 @@ static const struct input_id goodix_berlin_i2c_input_id = { static int goodix_berlin_i2c_probe(struct i2c_client *client) { + const struct goodix_berlin_ic_data *ic_data = + i2c_get_match_data(client); struct regmap *regmap; int error; @@ -39,22 +41,28 @@ static int goodix_berlin_i2c_probe(struct i2c_client *client) return PTR_ERR(regmap); error = goodix_berlin_probe(&client->dev, client->irq, - &goodix_berlin_i2c_input_id, regmap); + &goodix_berlin_i2c_input_id, regmap, + ic_data); if (error) return error; return 0; } +static const struct goodix_berlin_ic_data gt9916_data = { + .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D, + .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D, +}; + static const struct i2c_device_id goodix_berlin_i2c_id[] = { - { "gt9916" }, + { .name = "gt9916", .driver_data = (long)>9916_data }, { } }; MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id); static const struct of_device_id goodix_berlin_i2c_of_match[] = { - { .compatible = "goodix,gt9916", }, + { .compatible = "goodix,gt9916", .data = >9916_data }, { } }; MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match); diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c index 0662e87b8692..01f850f484c2 100644 --- a/drivers/input/touchscreen/goodix_berlin_spi.c +++ b/drivers/input/touchscreen/goodix_berlin_spi.c @@ -18,10 +18,14 @@ #define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1 #define GOODIX_BERLIN_REGISTER_WIDTH 4 -#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3 -#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ +#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A 4 +#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D 3 +#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ GOODIX_BERLIN_REGISTER_WIDTH + \ - GOODIX_BERLIN_SPI_READ_DUMMY_LEN) + GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A) +#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ + GOODIX_BERLIN_REGISTER_WIDTH + \ + GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D) #define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \ GOODIX_BERLIN_REGISTER_WIDTH) @@ -33,6 +37,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf, size_t val_size) { struct spi_device *spi = context; + const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi); struct spi_transfer xfers; struct spi_message spi_msg; const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */ @@ -42,23 +47,22 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf, return -EINVAL; u8 *buf __free(kfree) = - kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size, - GFP_KERNEL); + kzalloc(ic_data->read_prefix_len + val_size, GFP_KERNEL); if (!buf) return -ENOMEM; spi_message_init(&spi_msg); memset(&xfers, 0, sizeof(xfers)); - /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */ + /* buffer format: 0xF1 + addr(4bytes) + dummy(3/4bytes) + data */ buf[0] = GOODIX_BERLIN_SPI_READ_FLAG; put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN); memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH, - 0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN); + 0xff, ic_data->read_dummy_len); xfers.tx_buf = buf; xfers.rx_buf = buf; - xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size; + xfers.len = ic_data->read_prefix_len + val_size; xfers.cs_change = 0; spi_message_add_tail(&xfers, &spi_msg); @@ -68,7 +72,7 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf, return error; } - memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size); + memcpy(val_buf, buf + ic_data->read_prefix_len, val_size); return error; } @@ -123,6 +127,7 @@ static const struct input_id goodix_berlin_spi_input_id = { static int goodix_berlin_spi_probe(struct spi_device *spi) { + const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi); struct regmap_config regmap_config; struct regmap *regmap; size_t max_size; @@ -137,7 +142,7 @@ static int goodix_berlin_spi_probe(struct spi_device *spi) max_size = spi_max_transfer_size(spi); regmap_config = goodix_berlin_spi_regmap_conf; - regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN; + regmap_config.max_raw_read = max_size - ic_data->read_prefix_len; regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN; regmap = devm_regmap_init(&spi->dev, NULL, spi, ®map_config); @@ -145,21 +150,38 @@ static int goodix_berlin_spi_probe(struct spi_device *spi) return PTR_ERR(regmap); error = goodix_berlin_probe(&spi->dev, spi->irq, - &goodix_berlin_spi_input_id, regmap); + &goodix_berlin_spi_input_id, regmap, + ic_data); if (error) return error; return 0; } +static const struct goodix_berlin_ic_data gt9897_data = { + .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A, + .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_A, + .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A, + .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A, +}; + +static const struct goodix_berlin_ic_data gt9916_data = { + .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D, + .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D, + .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D, + .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D, +}; + static const struct spi_device_id goodix_berlin_spi_ids[] = { - { "gt9916" }, + { .name = "gt9897", .driver_data = (long)>9897_data }, + { .name = "gt9916", .driver_data = (long)>9916_data }, { }, }; MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids); static const struct of_device_id goodix_berlin_spi_of_match[] = { - { .compatible = "goodix,gt9916", }, + { .compatible = "goodix,gt9897", .data = >9897_data }, + { .compatible = "goodix,gt9916", .data = >9916_data }, { } }; MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match); diff --git a/drivers/input/touchscreen/goodix_fwupload.c b/drivers/input/touchscreen/goodix_fwupload.c index 191d4f38d991..5ae9a109ba0d 100644 --- a/drivers/input/touchscreen/goodix_fwupload.c +++ b/drivers/input/touchscreen/goodix_fwupload.c @@ -188,13 +188,13 @@ static int goodix_start_firmware(struct i2c_client *client) static int goodix_firmware_upload(struct goodix_ts_data *ts) { - const struct firmware *fw; char fw_name[64]; const u8 *data; int error; snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name); + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_name, &ts->client->dev); if (error) { dev_err(&ts->client->dev, "Firmware request error %d\n", error); @@ -203,60 +203,61 @@ static int goodix_firmware_upload(struct goodix_ts_data *ts) error = goodix_firmware_verify(&ts->client->dev, fw); if (error) - goto release; + return error; error = goodix_reset_no_int_sync(ts); if (error) - goto release; + return error; error = goodix_enter_upload_mode(ts->client); if (error) - goto release; + return error; /* Select SRAM bank 0 and upload section 1 & 2 */ error = goodix_i2c_write_u8(ts->client, GOODIX_REG_MISCTL_SRAM_BANK, 0x00); if (error) - goto release; + return error; data = fw->data + GOODIX_FW_HEADER_LENGTH; error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, data, 2 * GOODIX_FW_SECTION_LENGTH); if (error) - goto release; + return error; /* Select SRAM bank 1 and upload section 3 & 4 */ error = goodix_i2c_write_u8(ts->client, GOODIX_REG_MISCTL_SRAM_BANK, 0x01); if (error) - goto release; + return error; data += 2 * GOODIX_FW_SECTION_LENGTH; error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, data, 2 * GOODIX_FW_SECTION_LENGTH); if (error) - goto release; + return error; /* Select SRAM bank 2 and upload the DSP firmware */ error = goodix_i2c_write_u8(ts->client, GOODIX_REG_MISCTL_SRAM_BANK, 0x02); if (error) - goto release; + return error; data += 2 * GOODIX_FW_SECTION_LENGTH; error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS, data, GOODIX_FW_DSP_LENGTH); if (error) - goto release; + return error; error = goodix_start_firmware(ts->client); if (error) - goto release; + return error; error = goodix_int_sync(ts); -release: - release_firmware(fw); - return error; + if (error) + return error; + + return 0; } static int goodix_prepare_bak_ref(struct goodix_ts_data *ts) diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index dbf92fb02f80..2baeb4f3b941 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -97,7 +97,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - gunze = kzalloc(sizeof(*gunze), GFP_KERNEL); + gunze = kzalloc_obj(*gunze); input_dev = input_allocate_device(); if (!gunze || !input_dev) { err = -ENOMEM; @@ -106,7 +106,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv) gunze->serio = serio; gunze->dev = input_dev; - snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); + scnprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys); input_dev->name = "Gunze AHL-51S TouchScreen"; input_dev->phys = gunze->phys; diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c index dc0a2482ddd6..394ae8c88d50 100644 --- a/drivers/input/touchscreen/hampshire.c +++ b/drivers/input/touchscreen/hampshire.c @@ -109,7 +109,7 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - phampshire = kzalloc(sizeof(*phampshire), GFP_KERNEL); + phampshire = kzalloc_obj(*phampshire); input_dev = input_allocate_device(); if (!phampshire || !input_dev) { err = -ENOMEM; @@ -118,8 +118,8 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv) phampshire->serio = serio; phampshire->dev = input_dev; - snprintf(phampshire->phys, sizeof(phampshire->phys), - "%s/input0", serio->phys); + scnprintf(phampshire->phys, sizeof(phampshire->phys), + "%s/input0", serio->phys); input_dev->name = "Hampshire Serial TouchScreen"; input_dev->phys = phampshire->phys; diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index a73369e15dda..62041bcca83d 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -869,8 +869,6 @@ static ssize_t hideep_update_fw(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct hideep_ts *ts = i2c_get_clientdata(client); - const struct firmware *fw_entry; - char *fw_name; int mode; int error; @@ -878,46 +876,42 @@ static ssize_t hideep_update_fw(struct device *dev, if (error) return error; - fw_name = kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin", - be16_to_cpu(ts->dwz_info.product_id)); + const char *fw_name __free(kfree) = + kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin", + be16_to_cpu(ts->dwz_info.product_id)); if (!fw_name) return -ENOMEM; + const struct firmware *fw_entry __free(firmware) = NULL; error = request_firmware(&fw_entry, fw_name, dev); if (error) { dev_err(dev, "failed to request firmware %s: %d", fw_name, error); - goto out_free_fw_name; + return error; } if (fw_entry->size % sizeof(__be32)) { dev_err(dev, "invalid firmware size %zu\n", fw_entry->size); - error = -EINVAL; - goto out_release_fw; + return -EINVAL; } if (fw_entry->size > ts->fw_size) { dev_err(dev, "fw size (%zu) is too big (memory size %d)\n", fw_entry->size, ts->fw_size); - error = -EFBIG; - goto out_release_fw; + return -EFBIG; } - mutex_lock(&ts->dev_mutex); - disable_irq(client->irq); - - error = hideep_update_firmware(ts, (const __be32 *)fw_entry->data, - fw_entry->size); - - enable_irq(client->irq); - mutex_unlock(&ts->dev_mutex); + scoped_guard(mutex, &ts->dev_mutex) { + guard(disable_irq)(&client->irq); -out_release_fw: - release_firmware(fw_entry); -out_free_fw_name: - kfree(fw_name); + error = hideep_update_firmware(ts, + (const __be32 *)fw_entry->data, + fw_entry->size); + if (error) + return error; + } - return error ?: count; + return count; } static ssize_t hideep_fw_version_show(struct device *dev, @@ -925,13 +919,9 @@ static ssize_t hideep_fw_version_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct hideep_ts *ts = i2c_get_clientdata(client); - ssize_t len; - mutex_lock(&ts->dev_mutex); - len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver)); - mutex_unlock(&ts->dev_mutex); - - return len; + guard(mutex)(&ts->dev_mutex); + return sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver)); } static ssize_t hideep_product_id_show(struct device *dev, @@ -939,13 +929,9 @@ static ssize_t hideep_product_id_show(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct hideep_ts *ts = i2c_get_clientdata(client); - ssize_t len; - - mutex_lock(&ts->dev_mutex); - len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id)); - mutex_unlock(&ts->dev_mutex); - return len; + guard(mutex)(&ts->dev_mutex); + return sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id)); } static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL); diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c new file mode 100644 index 000000000000..83c60e137a55 --- /dev/null +++ b/drivers/input/touchscreen/himax_hx852x.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Himax HX852x(ES) Touchscreen Driver + * Copyright (c) 2020-2024 Stephan Gerhold <stephan@gerhold.net> + * Copyright (c) 2020 Jonathan Albrieux <jonathan.albrieux@gmail.com> + * + * Based on the Himax Android Driver Sample Code Ver 0.3 for HMX852xES chipset: + * Copyright (c) 2014 Himax Corporation. + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.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/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + +#define HX852X_COORD_SIZE(fingers) ((fingers) * sizeof(struct hx852x_coord)) +#define HX852X_WIDTH_SIZE(fingers) ALIGN(fingers, 4) +#define HX852X_BUF_SIZE(fingers) (HX852X_COORD_SIZE(fingers) + \ + HX852X_WIDTH_SIZE(fingers) + \ + sizeof(struct hx852x_touch_info)) + +#define HX852X_MAX_FINGERS 12 +#define HX852X_MAX_KEY_COUNT 4 +#define HX852X_MAX_BUF_SIZE HX852X_BUF_SIZE(HX852X_MAX_FINGERS) + +#define HX852X_TS_SLEEP_IN 0x80 +#define HX852X_TS_SLEEP_OUT 0x81 +#define HX852X_TS_SENSE_OFF 0x82 +#define HX852X_TS_SENSE_ON 0x83 +#define HX852X_READ_ONE_EVENT 0x85 +#define HX852X_READ_ALL_EVENTS 0x86 +#define HX852X_READ_LATEST_EVENT 0x87 +#define HX852X_CLEAR_EVENT_STACK 0x88 + +#define HX852X_REG_SRAM_SWITCH 0x8c +#define HX852X_REG_SRAM_ADDR 0x8b +#define HX852X_REG_FLASH_RPLACE 0x5a + +#define HX852X_SRAM_SWITCH_TEST_MODE 0x14 +#define HX852X_SRAM_ADDR_CONFIG 0x7000 + +struct hx852x { + struct i2c_client *client; + struct input_dev *input_dev; + struct touchscreen_properties props; + struct gpio_desc *reset_gpiod; + struct regulator_bulk_data supplies[2]; + unsigned int max_fingers; + unsigned int keycount; + unsigned int keycodes[HX852X_MAX_KEY_COUNT]; +}; + +struct hx852x_config { + u8 rx_num; + u8 tx_num; + u8 max_pt; + u8 padding1[3]; + __be16 x_res; + __be16 y_res; + u8 padding2[2]; +} __packed __aligned(4); + +struct hx852x_coord { + __be16 x; + __be16 y; +} __packed __aligned(4); + +struct hx852x_touch_info { + u8 finger_num; + __le16 finger_pressed; + u8 padding; +} __packed __aligned(4); + +static int hx852x_i2c_read(struct hx852x *hx, u8 cmd, void *data, u16 len) +{ + struct i2c_client *client = hx->client; + int error; + int ret; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &cmd, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + error = ret < 0 ? ret : -EIO; + dev_err(&client->dev, "failed to read %#x: %d\n", cmd, error); + return error; + } + + return 0; +} + +static int hx852x_power_on(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = regulator_bulk_enable(ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) { + dev_err(dev, "failed to enable regulators: %d\n", error); + return error; + } + + gpiod_set_value_cansleep(hx->reset_gpiod, 1); + msleep(20); + gpiod_set_value_cansleep(hx->reset_gpiod, 0); + msleep(50); + + return 0; +} + +static int hx852x_start(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_OUT); + if (error) { + dev_err(dev, "failed to send TS_SLEEP_OUT: %d\n", error); + return error; + } + msleep(30); + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_ON); + if (error) { + dev_err(dev, "failed to send TS_SENSE_ON: %d\n", error); + return error; + } + msleep(20); + + return 0; +} + +static int hx852x_stop(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_OFF); + if (error) { + dev_err(dev, "failed to send TS_SENSE_OFF: %d\n", error); + return error; + } + msleep(20); + + error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_IN); + if (error) { + dev_err(dev, "failed to send TS_SLEEP_IN: %d\n", error); + return error; + } + msleep(30); + + return 0; +} + +static int hx852x_power_off(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error; + + error = regulator_bulk_disable(ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) { + dev_err(dev, "failed to disable regulators: %d\n", error); + return error; + } + + return 0; +} + +static int hx852x_read_config(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + struct hx852x_config conf; + int x_res, y_res; + int error, error2; + + error = hx852x_power_on(hx); + if (error) + return error; + + /* Sensing must be turned on briefly to load the config */ + error = hx852x_start(hx); + if (error) + goto err_power_off; + + error = hx852x_stop(hx); + if (error) + goto err_power_off; + + error = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, + HX852X_SRAM_SWITCH_TEST_MODE); + if (error) + goto err_power_off; + + error = i2c_smbus_write_word_data(hx->client, HX852X_REG_SRAM_ADDR, + HX852X_SRAM_ADDR_CONFIG); + if (error) + goto err_test_mode; + + error = hx852x_i2c_read(hx, HX852X_REG_FLASH_RPLACE, &conf, sizeof(conf)); + if (error) + goto err_test_mode; + + x_res = be16_to_cpu(conf.x_res); + y_res = be16_to_cpu(conf.y_res); + hx->max_fingers = (conf.max_pt & 0xf0) >> 4; + dev_dbg(dev, "x res: %u, y res: %u, max fingers: %u\n", + x_res, y_res, hx->max_fingers); + + if (hx->max_fingers > HX852X_MAX_FINGERS) { + dev_err(dev, "max supported fingers: %u, found: %u\n", + HX852X_MAX_FINGERS, hx->max_fingers); + error = -EINVAL; + goto err_test_mode; + } + + if (x_res && y_res) { + input_set_abs_params(hx->input_dev, ABS_MT_POSITION_X, 0, x_res - 1, 0, 0); + input_set_abs_params(hx->input_dev, ABS_MT_POSITION_Y, 0, y_res - 1, 0, 0); + } + +err_test_mode: + error2 = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, 0); + error = error ?: error2; +err_power_off: + error2 = hx852x_power_off(hx); + return error ?: error2; +} + +static int hx852x_handle_events(struct hx852x *hx) +{ + /* + * The event packets have variable size, depending on the amount of + * supported fingers (hx->max_fingers). They are laid out as follows: + * - struct hx852x_coord[hx->max_fingers]: Coordinates for each finger + * - u8[ALIGN(hx->max_fingers, 4)]: Touch width for each finger + * with padding for 32-bit alignment + * - struct hx852x_touch_info + * + * Load everything into a 32-bit aligned buffer so the coordinates + * can be assigned directly, without using get_unaligned_*(). + */ + u8 buf[HX852X_MAX_BUF_SIZE] __aligned(4); + struct hx852x_coord *coord = (struct hx852x_coord *)buf; + u8 *width = &buf[HX852X_COORD_SIZE(hx->max_fingers)]; + struct hx852x_touch_info *info = (struct hx852x_touch_info *) + &width[HX852X_WIDTH_SIZE(hx->max_fingers)]; + unsigned long finger_pressed, key_pressed; + unsigned int i, x, y, w; + int error; + + error = hx852x_i2c_read(hx, HX852X_READ_ALL_EVENTS, buf, + HX852X_BUF_SIZE(hx->max_fingers)); + if (error) + return error; + + finger_pressed = get_unaligned_le16(&info->finger_pressed); + key_pressed = finger_pressed >> HX852X_MAX_FINGERS; + + /* All bits are set when no touch is detected */ + if (info->finger_num == 0xff || !(info->finger_num & 0x0f)) + finger_pressed = 0; + if (key_pressed == 0xf) + key_pressed = 0; + + for_each_set_bit(i, &finger_pressed, hx->max_fingers) { + x = be16_to_cpu(coord[i].x); + y = be16_to_cpu(coord[i].y); + w = width[i]; + + input_mt_slot(hx->input_dev, i); + input_mt_report_slot_state(hx->input_dev, MT_TOOL_FINGER, 1); + touchscreen_report_pos(hx->input_dev, &hx->props, x, y, true); + input_report_abs(hx->input_dev, ABS_MT_TOUCH_MAJOR, w); + } + input_mt_sync_frame(hx->input_dev); + + for (i = 0; i < hx->keycount; i++) + input_report_key(hx->input_dev, hx->keycodes[i], key_pressed & BIT(i)); + + input_sync(hx->input_dev); + return 0; +} + +static irqreturn_t hx852x_interrupt(int irq, void *ptr) +{ + struct hx852x *hx = ptr; + int error; + + error = hx852x_handle_events(hx); + if (error) { + dev_err_ratelimited(&hx->client->dev, + "failed to handle events: %d\n", error); + return IRQ_NONE; + } + + return IRQ_HANDLED; +} + +static int hx852x_input_open(struct input_dev *dev) +{ + struct hx852x *hx = input_get_drvdata(dev); + int error; + + error = hx852x_power_on(hx); + if (error) + return error; + + error = hx852x_start(hx); + if (error) { + hx852x_power_off(hx); + return error; + } + + enable_irq(hx->client->irq); + return 0; +} + +static void hx852x_input_close(struct input_dev *dev) +{ + struct hx852x *hx = input_get_drvdata(dev); + + hx852x_stop(hx); + disable_irq(hx->client->irq); + hx852x_power_off(hx); +} + +static int hx852x_parse_properties(struct hx852x *hx) +{ + struct device *dev = &hx->client->dev; + int error, count; + + count = device_property_count_u32(dev, "linux,keycodes"); + if (count == -EINVAL) { + /* Property does not exist, keycodes are optional */ + return 0; + } else if (count < 0) { + dev_err(dev, "Failed to read linux,keycodes: %d\n", count); + return count; + } else if (count > HX852X_MAX_KEY_COUNT) { + dev_err(dev, "max supported keys: %u, found: %u\n", + HX852X_MAX_KEY_COUNT, hx->keycount); + return -EINVAL; + } + hx->keycount = count; + + error = device_property_read_u32_array(dev, "linux,keycodes", + hx->keycodes, hx->keycount); + if (error) { + dev_err(dev, "failed to read linux,keycodes: %d\n", error); + return error; + } + + return 0; +} + +static int hx852x_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct hx852x *hx; + int error, i; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_WORD_DATA)) { + dev_err(dev, "not all required i2c functionality supported\n"); + return -ENXIO; + } + + hx = devm_kzalloc(dev, sizeof(*hx), GFP_KERNEL); + if (!hx) + return -ENOMEM; + + hx->client = client; + hx->input_dev = devm_input_allocate_device(dev); + if (!hx->input_dev) + return -ENOMEM; + + hx->input_dev->name = "Himax HX852x"; + hx->input_dev->id.bustype = BUS_I2C; + hx->input_dev->open = hx852x_input_open; + hx->input_dev->close = hx852x_input_close; + + i2c_set_clientdata(client, hx); + input_set_drvdata(hx->input_dev, hx); + + hx->supplies[0].supply = "vcca"; + hx->supplies[1].supply = "vccd"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->supplies), hx->supplies); + if (error) + return dev_err_probe(dev, error, "failed to get regulators\n"); + + hx->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(hx->reset_gpiod)) + return dev_err_probe(dev, PTR_ERR(hx->reset_gpiod), + "failed to get reset gpio\n"); + + error = devm_request_threaded_irq(dev, client->irq, NULL, hx852x_interrupt, + IRQF_ONESHOT | IRQF_NO_AUTOEN, NULL, hx); + if (error) + return dev_err_probe(dev, error, "failed to request irq %d", client->irq); + + error = hx852x_read_config(hx); + if (error) + return error; + + input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_Y); + input_set_abs_params(hx->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + touchscreen_parse_properties(hx->input_dev, true, &hx->props); + error = hx852x_parse_properties(hx); + if (error) + return error; + + hx->input_dev->keycode = hx->keycodes; + hx->input_dev->keycodemax = hx->keycount; + hx->input_dev->keycodesize = sizeof(hx->keycodes[0]); + for (i = 0; i < hx->keycount; i++) + input_set_capability(hx->input_dev, EV_KEY, hx->keycodes[i]); + + error = input_mt_init_slots(hx->input_dev, hx->max_fingers, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return dev_err_probe(dev, error, "failed to init MT slots\n"); + + error = input_register_device(hx->input_dev); + if (error) + return dev_err_probe(dev, error, "failed to register input device\n"); + + return 0; +} + +static int hx852x_suspend(struct device *dev) +{ + struct hx852x *hx = dev_get_drvdata(dev); + + guard(mutex)(&hx->input_dev->mutex); + + if (input_device_enabled(hx->input_dev)) + return hx852x_stop(hx); + + return 0; +} + +static int hx852x_resume(struct device *dev) +{ + struct hx852x *hx = dev_get_drvdata(dev); + + guard(mutex)(&hx->input_dev->mutex); + + if (input_device_enabled(hx->input_dev)) + return hx852x_start(hx); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(hx852x_pm_ops, hx852x_suspend, hx852x_resume); + +#ifdef CONFIG_OF +static const struct of_device_id hx852x_of_match[] = { + { .compatible = "himax,hx852es" }, + { } +}; +MODULE_DEVICE_TABLE(of, hx852x_of_match); +#endif + +static struct i2c_driver hx852x_driver = { + .probe = hx852x_probe, + .driver = { + .name = "himax_hx852x", + .pm = pm_sleep_ptr(&hx852x_pm_ops), + .of_match_table = of_match_ptr(hx852x_of_match), + }, +}; +module_i2c_driver(hx852x_driver); + +MODULE_DESCRIPTION("Himax HX852x(ES) Touchscreen Driver"); +MODULE_AUTHOR("Jonathan Albrieux <jonathan.albrieux@gmail.com>"); +MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c index b2ff7a45b908..1513f20cbf51 100644 --- a/drivers/input/touchscreen/hycon-hy46xx.c +++ b/drivers/input/touchscreen/hycon-hy46xx.c @@ -181,18 +181,17 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev, struct hycon_hy46xx_attribute *attr = container_of(dattr, struct hycon_hy46xx_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; - size_t count = 0; int error = 0; int val; - mutex_lock(&tsdata->mutex); + guard(mutex)(&tsdata->mutex); error = regmap_read(tsdata->regmap, attr->address, &val); - if (error < 0) { + if (error) { dev_err(&tsdata->client->dev, "Failed to fetch attribute %s, error %d\n", dattr->attr.name, error); - goto out; + return error; } if (val != *field) { @@ -202,11 +201,7 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev, *field = val; } - count = sysfs_emit(buf, "%d\n", val); - -out: - mutex_unlock(&tsdata->mutex); - return error ?: count; + return sysfs_emit(buf, "%d\n", val); } static ssize_t hycon_hy46xx_setting_store(struct device *dev, @@ -221,29 +216,25 @@ static ssize_t hycon_hy46xx_setting_store(struct device *dev, unsigned int val; int error; - mutex_lock(&tsdata->mutex); + guard(mutex)(&tsdata->mutex); error = kstrtouint(buf, 0, &val); if (error) - goto out; + return error; - if (val < attr->limit_low || val > attr->limit_high) { - error = -ERANGE; - goto out; - } + if (val < attr->limit_low || val > attr->limit_high) + return -ERANGE; error = regmap_write(tsdata->regmap, attr->address, val); - if (error < 0) { + if (error) { dev_err(&tsdata->client->dev, "Failed to update attribute %s, error: %d\n", dattr->attr.name, error); - goto out; + return error; } *field = val; -out: - mutex_unlock(&tsdata->mutex); - return error ?: count; + return count; } static HYCON_ATTR_U8(threshold, 0644, HY46XX_THRESHOLD, 0, 255); diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c new file mode 100644 index 000000000000..b64d7928e18f --- /dev/null +++ b/drivers/input/touchscreen/hynitron-cst816x.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for I2C connected Hynitron CST816x Series Touchscreen + * + * Copyright (C) 2025 Oleh Kuzhylnyi <kuzhylol@gmail.com> + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/unaligned.h> +#include <linux/interrupt.h> +#include <linux/module.h> + +#define CST816X_RD_REG 0x01 +#define CST816X_NUM_KEYS 5 + +struct cst816x_touch { + u8 gest; + u8 active; + u16 abs_x; + u16 abs_y; +} __packed; + +struct cst816x_priv { + struct i2c_client *client; + struct gpio_desc *reset; + struct input_dev *input; + unsigned int keycode[CST816X_NUM_KEYS]; + unsigned int keycodemax; +}; + +static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv) +{ + int count; + int error; + + if (device_property_present(dev, "linux,keycodes")) { + count = device_property_count_u32(dev, "linux,keycodes"); + if (count < 0) { + error = count; + dev_err(dev, "failed to count keys: %d\n", error); + return error; + } else if (count > ARRAY_SIZE(priv->keycode)) { + dev_err(dev, "too many keys defined: %d\n", count); + return -EINVAL; + } + priv->keycodemax = count; + + error = device_property_read_u32_array(dev, "linux,keycodes", + priv->keycode, + priv->keycodemax); + if (error) { + dev_err(dev, "failed to read keycodes: %d\n", error); + return error; + } + } + + return 0; +} + +static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg, + void *buf, size_t len) +{ + struct i2c_msg xfer[] = { + { + .addr = priv->client->addr, + .flags = 0, + .buf = ®, + .len = sizeof(reg), + }, + { + .addr = priv->client->addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len, + }, + }; + int error; + int ret; + + ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer)); + if (ret != ARRAY_SIZE(xfer)) { + error = ret < 0 ? ret : -EIO; + dev_err(&priv->client->dev, "i2c rx err: %d\n", error); + return error; + } + + return 0; +} + +static u8 cst816x_gest_idx(u8 gest) +{ + u8 index; + + switch (gest) { + case 0x01: /* Slide up gesture */ + case 0x02: /* Slide down gesture */ + case 0x03: /* Slide left gesture */ + case 0x04: /* Slide right gesture */ + index = gest; + break; + case 0x0c: /* Long press gesture */ + default: + index = CST816X_NUM_KEYS; + break; + } + + return index - 1; +} + +static bool cst816x_process_touch(struct cst816x_priv *priv, + struct cst816x_touch *tch) +{ + if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch))) + return false; + + tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0); + tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0); + + dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n", + tch->abs_x, tch->abs_y, tch->active, tch->gest); + + return true; +} + +static int cst816x_register_input(struct cst816x_priv *priv) +{ + priv->input = devm_input_allocate_device(&priv->client->dev); + if (!priv->input) + return -ENOMEM; + + priv->input->name = "Hynitron CST816x Series Touchscreen"; + priv->input->phys = "input/ts"; + priv->input->id.bustype = BUS_I2C; + + input_set_drvdata(priv->input, priv); + + input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0); + input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0); + input_set_capability(priv->input, EV_KEY, BTN_TOUCH); + + priv->input->keycode = priv->keycode; + priv->input->keycodesize = sizeof(priv->keycode[0]); + priv->input->keycodemax = priv->keycodemax; + + for (int i = 0; i < priv->keycodemax; i++) { + if (priv->keycode[i] == KEY_RESERVED) + continue; + + input_set_capability(priv->input, EV_KEY, priv->keycode[i]); + } + + return input_register_device(priv->input); +} + +static void cst816x_reset(struct cst816x_priv *priv) +{ + gpiod_set_value_cansleep(priv->reset, 1); + msleep(50); + gpiod_set_value_cansleep(priv->reset, 0); + msleep(100); +} + +static irqreturn_t cst816x_irq_cb(int irq, void *cookie) +{ + struct cst816x_priv *priv = cookie; + struct cst816x_touch tch; + + if (!cst816x_process_touch(priv, &tch)) + return IRQ_HANDLED; + + input_report_abs(priv->input, ABS_X, tch.abs_x); + input_report_abs(priv->input, ABS_Y, tch.abs_y); + + if (tch.gest) + input_report_key(priv->input, + priv->keycode[cst816x_gest_idx(tch.gest)], + tch.active); + + input_report_key(priv->input, BTN_TOUCH, tch.active); + + input_sync(priv->input); + + return IRQ_HANDLED; +} + +static int cst816x_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct cst816x_priv *priv; + int error; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = client; + + priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(priv->reset)) + return dev_err_probe(dev, PTR_ERR(priv->reset), + "gpio reset request failed\n"); + + if (priv->reset) + cst816x_reset(priv); + + error = cst816x_parse_keycodes(dev, priv); + if (error) + dev_warn(dev, "no gestures found in dt\n"); + + error = cst816x_register_input(priv); + if (error) + return dev_err_probe(dev, error, "input register failed\n"); + + error = devm_request_threaded_irq(dev, client->irq, + NULL, cst816x_irq_cb, IRQF_ONESHOT, + dev_driver_string(dev), priv); + if (error) + return dev_err_probe(dev, error, "irq request failed\n"); + + return 0; +} + +static const struct i2c_device_id cst816x_id[] = { + { .name = "cst816s", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cst816x_id); + +static const struct of_device_id cst816x_of_match[] = { + { .compatible = "hynitron,cst816s", }, + { } +}; +MODULE_DEVICE_TABLE(of, cst816x_of_match); + +static struct i2c_driver cst816x_driver = { + .driver = { + .name = "cst816x", + .of_match_table = cst816x_of_match, + }, + .id_table = cst816x_id, + .probe = cst816x_probe, +}; + +module_i2c_driver(cst816x_driver); + +MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>"); +MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index fa38d70aded7..3bf524a6ee20 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -327,9 +327,8 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) return contact; } -static irqreturn_t ili210x_irq(int irq, void *irq_data) +static void ili210x_process_events(struct ili210x *priv) { - struct ili210x *priv = irq_data; struct i2c_client *client = priv->client; const struct ili2xxx_chip *chip = priv->chip; u8 touchdata[ILI210X_DATA_SIZE] = { 0 }; @@ -356,8 +355,22 @@ static irqreturn_t ili210x_irq(int irq, void *irq_data) usleep_range(time_delta, time_delta + 1000); } } while (!priv->stop && keep_polling); +} + +static irqreturn_t ili210x_irq(int irq, void *irq_data) +{ + struct ili210x *priv = irq_data; + + ili210x_process_events(priv); return IRQ_HANDLED; +}; + +static void ili210x_work_i2c_poll(struct input_dev *input) +{ + struct ili210x *priv = input_get_drvdata(input); + + ili210x_process_events(priv); } static int ili251x_firmware_update_resolution(struct device *dev) @@ -829,12 +842,32 @@ static int ili210x_do_firmware_update(struct ili210x *priv, return 0; } +static ssize_t ili210x_firmware_update(struct device *dev, const u8 *fwbuf, + u16 ac_end, u16 df_end) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ili210x *priv = i2c_get_clientdata(client); + const char *fwname = ILI251X_FW_FILENAME; + int error; + + dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname); + + ili210x_hardware_reset(priv->reset_gpio); + + error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end); + + ili210x_hardware_reset(priv->reset_gpio); + + dev_dbg(dev, "Firmware update ended, error=%i\n", error); + + return error; +} + static ssize_t ili210x_firmware_update_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - struct ili210x *priv = i2c_get_clientdata(client); const char *fwname = ILI251X_FW_FILENAME; u16 ac_end, df_end; int error; @@ -860,16 +893,11 @@ static ssize_t ili210x_firmware_update_store(struct device *dev, * the touch controller to disable the IRQs during update, so we have * to do it this way here. */ - scoped_guard(disable_irq, &client->irq) { - dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname); - - ili210x_hardware_reset(priv->reset_gpio); - - error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end); - - ili210x_hardware_reset(priv->reset_gpio); - - dev_dbg(dev, "Firmware update ended, error=%i\n", error); + if (client->irq > 0) { + guard(disable_irq)(&client->irq); + error = ili210x_firmware_update(dev, fwbuf, ac_end, df_end); + } else { + error = ili210x_firmware_update(dev, fwbuf, ac_end, df_end); } return error ?: count; @@ -942,15 +970,8 @@ static int ili210x_i2c_probe(struct i2c_client *client) chip = device_get_match_data(dev); if (!chip && id) chip = (const struct ili2xxx_chip *)id->driver_data; - if (!chip) { - dev_err(&client->dev, "unknown device model\n"); - return -ENODEV; - } - - if (client->irq <= 0) { - dev_err(dev, "No IRQ!\n"); - return -EINVAL; - } + if (!chip) + return dev_err_probe(&client->dev, -ENODEV, "unknown device model\n"); reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(reset_gpio)) @@ -998,17 +1019,22 @@ static int ili210x_i2c_probe(struct i2c_client *client) error = input_mt_init_slots(input, priv->chip->max_touches, INPUT_MT_DIRECT); - if (error) { - dev_err(dev, "Unable to set up slots, err: %d\n", error); - return error; - } + if (error) + return dev_err_probe(dev, error, "Unable to set up slots\n"); - error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, - IRQF_ONESHOT, client->name, priv); - if (error) { - dev_err(dev, "Unable to request touchscreen IRQ, err: %d\n", - error); - return error; + input_set_drvdata(input, priv); + + if (client->irq > 0) { + error = devm_request_threaded_irq(dev, client->irq, NULL, ili210x_irq, + IRQF_ONESHOT, client->name, priv); + if (error) + return dev_err_probe(dev, error, "Unable to request touchscreen IRQ\n"); + } else { + error = input_setup_polling(input, ili210x_work_i2c_poll); + if (error) + return dev_err_probe(dev, error, "Could not set up polling mode\n"); + + input_set_poll_interval(input, ILI2XXX_POLL_PERIOD); } error = devm_add_action_or_reset(dev, ili210x_stop, priv); @@ -1016,10 +1042,8 @@ static int ili210x_i2c_probe(struct i2c_client *client) return error; error = input_register_device(priv->input); - if (error) { - dev_err(dev, "Cannot register input device, err: %d\n", error); - return error; - } + if (error) + return dev_err_probe(dev, error, "Cannot register input device\n"); return 0; } diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index 0dd632724a00..0706443792ba 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -122,7 +122,7 @@ static int ilitek_i2c_write_and_read(struct ilitek_ts_data *ts, return error; } if (delay > 0) - mdelay(delay); + fsleep(delay * 1000); if (read_len > 0) { error = i2c_transfer(client->adapter, msgs + 1, 1); @@ -396,10 +396,10 @@ static const struct ilitek_protocol_map ptl_func_map[] = { static void ilitek_reset(struct ilitek_ts_data *ts, int delay) { if (ts->reset_gpio) { - gpiod_set_value(ts->reset_gpio, 1); - mdelay(10); - gpiod_set_value(ts->reset_gpio, 0); - mdelay(delay); + gpiod_set_value_cansleep(ts->reset_gpio, 1); + fsleep(10000); + gpiod_set_value_cansleep(ts->reset_gpio, 0); + fsleep(delay * 1000); } } diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index 3c8bbe284b73..7bbb00beec3b 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -366,32 +366,34 @@ static int imagis_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct imagis_ts *ts = i2c_get_clientdata(client); - int retval = 0; - - mutex_lock(&ts->input_dev->mutex); + int error; - if (input_device_enabled(ts->input_dev)) - retval = imagis_stop(ts); + guard(mutex)(&ts->input_dev->mutex); - mutex_unlock(&ts->input_dev->mutex); + if (input_device_enabled(ts->input_dev)) { + error = imagis_stop(ts); + if (error) + return error; + } - return retval; + return 0; } static int imagis_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct imagis_ts *ts = i2c_get_clientdata(client); - int retval = 0; - - mutex_lock(&ts->input_dev->mutex); + int error; - if (input_device_enabled(ts->input_dev)) - retval = imagis_start(ts); + guard(mutex)(&ts->input_dev->mutex); - mutex_unlock(&ts->input_dev->mutex); + if (input_device_enabled(ts->input_dev)) { + error = imagis_start(ts); + if (error) + return error; + } - return retval; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume); diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 6ac8fa84ed9f..43d6c69e3088 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -7,6 +7,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/bitfield.h> #include <linux/gpio/consumer.h> #include <linux/input.h> #include <linux/slab.h> @@ -20,25 +21,23 @@ #include <linux/log2.h> /* ADC configuration registers field define */ -#define ADC_AIEN (0x1 << 7) +#define ADC_AIEN BIT(7) +#define ADC_ADCH_MASK GENMASK(4, 0) #define ADC_CONV_DISABLE 0x1F -#define ADC_AVGE (0x1 << 5) -#define ADC_CAL (0x1 << 7) -#define ADC_CALF 0x2 -#define ADC_12BIT_MODE (0x2 << 2) -#define ADC_CONV_MODE_MASK (0x3 << 2) +#define ADC_AVGE BIT(5) +#define ADC_CAL BIT(7) +#define ADC_CALF BIT(1) +#define ADC_CONV_MODE_MASK GENMASK(3, 2) +#define ADC_12BIT_MODE 0x2 #define ADC_IPG_CLK 0x00 -#define ADC_INPUT_CLK_MASK 0x3 -#define ADC_CLK_DIV_8 (0x03 << 5) -#define ADC_CLK_DIV_MASK (0x3 << 5) -#define ADC_SHORT_SAMPLE_MODE (0x0 << 4) -#define ADC_SAMPLE_MODE_MASK (0x1 << 4) -#define ADC_HARDWARE_TRIGGER (0x1 << 13) -#define ADC_AVGS_SHIFT 14 -#define ADC_AVGS_MASK (0x3 << 14) +#define ADC_INPUT_CLK_MASK GENMASK(1, 0) +#define ADC_CLK_DIV_8 0x03 +#define ADC_CLK_DIV_MASK GENMASK(6, 5) +#define ADC_SAMPLE_MODE BIT(4) +#define ADC_HARDWARE_TRIGGER BIT(13) +#define ADC_AVGS_MASK GENMASK(15, 14) #define SELECT_CHANNEL_4 0x04 #define SELECT_CHANNEL_1 0x01 -#define DISABLE_CONVERSION_INT (0x0 << 7) /* ADC registers */ #define REG_ADC_HC0 0x00 @@ -55,7 +54,7 @@ #define ADC_TIMEOUT msecs_to_jiffies(100) /* TSC registers */ -#define REG_TSC_BASIC_SETING 0x00 +#define REG_TSC_BASIC_SETTING 0x00 #define REG_TSC_PRE_CHARGE_TIME 0x10 #define REG_TSC_FLOW_CONTROL 0x20 #define REG_TSC_MEASURE_VALUE 0x30 @@ -65,19 +64,26 @@ #define REG_TSC_DEBUG_MODE 0x70 #define REG_TSC_DEBUG_MODE2 0x80 +/* TSC_MEASURE_VALUE register field define */ +#define X_VALUE_MASK GENMASK(27, 16) +#define Y_VALUE_MASK GENMASK(11, 0) + /* TSC configuration registers field define */ -#define DETECT_4_WIRE_MODE (0x0 << 4) -#define AUTO_MEASURE 0x1 -#define MEASURE_SIGNAL 0x1 -#define DETECT_SIGNAL (0x1 << 4) -#define VALID_SIGNAL (0x1 << 8) -#define MEASURE_INT_EN 0x1 -#define MEASURE_SIG_EN 0x1 -#define VALID_SIG_EN (0x1 << 8) -#define DE_GLITCH_2 (0x2 << 29) -#define START_SENSE (0x1 << 12) -#define TSC_DISABLE (0x1 << 16) +#define MEASURE_DELAY_TIME_MASK GENMASK(31, 8) +#define DETECT_5_WIRE_MODE BIT(4) +#define AUTO_MEASURE BIT(0) +#define MEASURE_SIGNAL BIT(0) +#define DETECT_SIGNAL BIT(4) +#define VALID_SIGNAL BIT(8) +#define MEASURE_INT_EN BIT(0) +#define MEASURE_SIG_EN BIT(0) +#define VALID_SIG_EN BIT(8) +#define DE_GLITCH_MASK GENMASK(30, 29) +#define DE_GLITCH_DEF 0x02 +#define START_SENSE BIT(12) +#define TSC_DISABLE BIT(16) #define DETECT_MODE 0x2 +#define STATE_MACHINE_MASK GENMASK(22, 20) struct imx6ul_tsc { struct device *dev; @@ -92,6 +98,7 @@ struct imx6ul_tsc { u32 pre_charge_time; bool average_enable; u32 average_select; + u32 de_glitch; struct completion completion; }; @@ -112,19 +119,20 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK); - adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; - adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK); - adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; + adc_cfg |= FIELD_PREP(ADC_CONV_MODE_MASK, ADC_12BIT_MODE) | + FIELD_PREP(ADC_INPUT_CLK_MASK, ADC_IPG_CLK); + adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE); + adc_cfg |= FIELD_PREP(ADC_CLK_DIV_MASK, ADC_CLK_DIV_8); if (tsc->average_enable) { adc_cfg &= ~ADC_AVGS_MASK; - adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT; + adc_cfg |= FIELD_PREP(ADC_AVGS_MASK, tsc->average_select); } adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); /* enable calibration interrupt */ adc_hc |= ADC_AIEN; - adc_hc |= ADC_CONV_DISABLE; + adc_hc |= FIELD_PREP(ADC_ADCH_MASK, ADC_CONV_DISABLE); writel(adc_hc, tsc->adc_regs + REG_ADC_HC0); /* start ADC calibration */ @@ -164,19 +172,21 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) { u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; - adc_hc0 = DISABLE_CONVERSION_INT; + adc_hc0 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); - adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4; + adc_hc1 = FIELD_PREP(ADC_AIEN, 0) | + FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_4); writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1); - adc_hc2 = DISABLE_CONVERSION_INT; + adc_hc2 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2); - adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1; + adc_hc3 = FIELD_PREP(ADC_AIEN, 0) | + FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_1); writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3); - adc_hc4 = DISABLE_CONVERSION_INT; + adc_hc4 = FIELD_PREP(ADC_AIEN, 0); writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4); } @@ -188,13 +198,16 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) { u32 basic_setting = 0; + u32 debug_mode2; u32 start; - basic_setting |= tsc->measure_delay_time << 8; - basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; - writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING); + basic_setting |= FIELD_PREP(MEASURE_DELAY_TIME_MASK, + tsc->measure_delay_time); + basic_setting |= AUTO_MEASURE; + writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING); - writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); + debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, tsc->de_glitch); + writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME); writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN); @@ -250,7 +263,7 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) usleep_range(200, 400); debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2); - state_machine = (debug_mode2 >> 20) & 0x7; + state_machine = FIELD_GET(STATE_MACHINE_MASK, debug_mode2); } while (state_machine != DETECT_MODE); usleep_range(200, 400); @@ -278,8 +291,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id) if (status & MEASURE_SIGNAL) { value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE); - x = (value >> 16) & 0x0fff; - y = value & 0x0fff; + x = FIELD_GET(X_VALUE_MASK, value); + y = FIELD_GET(Y_VALUE_MASK, value); /* * In detect mode, we can get the xnur gpio value, @@ -379,6 +392,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) int tsc_irq; int adc_irq; u32 average_samples; + u32 de_glitch; tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL); if (!tsc) @@ -501,6 +515,25 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) return -EINVAL; } + err = of_property_read_u32(np, "debounce-delay-us", &de_glitch); + if (err) { + tsc->de_glitch = DE_GLITCH_DEF; + } else { + u64 cycles; + unsigned long rate = clk_get_rate(tsc->tsc_clk); + + cycles = DIV64_U64_ROUND_UP((u64)de_glitch * rate, USEC_PER_SEC); + + if (cycles <= 0x3ff) + tsc->de_glitch = 3; + else if (cycles <= 0x7ff) + tsc->de_glitch = 2; + else if (cycles <= 0xfff) + tsc->de_glitch = 1; + else + tsc->de_glitch = 0; + } + err = input_register_device(tsc->input); if (err) { dev_err(&pdev->dev, @@ -518,13 +551,11 @@ static int imx6ul_tsc_suspend(struct device *dev) struct imx6ul_tsc *tsc = platform_get_drvdata(pdev); struct input_dev *input_dev = tsc->input; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); if (input_device_enabled(input_dev)) imx6ul_tsc_stop(tsc); - mutex_unlock(&input_dev->mutex); - return 0; } @@ -533,16 +564,17 @@ static int imx6ul_tsc_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct imx6ul_tsc *tsc = platform_get_drvdata(pdev); struct input_dev *input_dev = tsc->input; - int retval = 0; - - mutex_lock(&input_dev->mutex); + int error; - if (input_device_enabled(input_dev)) - retval = imx6ul_tsc_start(tsc); + guard(mutex)(&input_dev->mutex); - mutex_unlock(&input_dev->mutex); + if (input_device_enabled(input_dev)) { + error = imx6ul_tsc_start(tsc); + if (error) + return error; + } - return retval; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops, diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c index 82f7ac62a4f2..ac3836ff2a30 100644 --- a/drivers/input/touchscreen/inexio.c +++ b/drivers/input/touchscreen/inexio.c @@ -114,7 +114,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - pinexio = kzalloc(sizeof(*pinexio), GFP_KERNEL); + pinexio = kzalloc_obj(*pinexio); input_dev = input_allocate_device(); if (!pinexio || !input_dev) { err = -ENOMEM; @@ -123,7 +123,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv) pinexio->serio = serio; pinexio->dev = input_dev; - snprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys); + scnprintf(pinexio->phys, sizeof(pinexio->phys), "%s/input0", serio->phys); input_dev->name = "iNexio Serial TouchScreen"; input_dev->phys = pinexio->phys; diff --git a/drivers/input/touchscreen/ipaq-micro-ts.c b/drivers/input/touchscreen/ipaq-micro-ts.c index 94720c41c9be..243e6465d9bd 100644 --- a/drivers/input/touchscreen/ipaq-micro-ts.c +++ b/drivers/input/touchscreen/ipaq-micro-ts.c @@ -47,7 +47,7 @@ static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable) { struct ipaq_micro *micro = ts->micro; - spin_lock_irq(µ->lock); + guard(spinlock_irq)(µ->lock); if (enable) { micro->ts = micro_ts_receive; @@ -56,8 +56,6 @@ static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable) micro->ts = NULL; micro->ts_data = NULL; } - - spin_unlock_irq(&ts->micro->lock); } static int micro_ts_open(struct input_dev *input) @@ -133,13 +131,11 @@ static int micro_ts_resume(struct device *dev) struct touchscreen_data *ts = dev_get_drvdata(dev); struct input_dev *input = ts->input; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) micro_ts_toggle_receive(ts, true); - mutex_unlock(&input->mutex); - return 0; } diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index 4ebd7565ae6e..587665e4e6fd 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -17,6 +17,7 @@ #include <linux/err.h> #include <linux/firmware.h> #include <linux/gpio/consumer.h> +#include <linux/hex.h> #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> @@ -72,8 +73,11 @@ #define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM) #define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM) -#define IQS5XX_REC_HDR_LEN 4 -#define IQS5XX_REC_LEN_MAX 255 +/* Length of firmware header in hexadecimal characters */ +#define IQS5XX_REC_HDR_LEN_HEX (1 /* start */ + 2 /* size */ + \ + 4 /* addr */ + 2 /* type */) +#define IQS5XX_REC_HDR_SIZE 4 /* size + addr (2 bytes) + type, in bytes*/ +#define IQS5XX_REC_DATA_SIZE 255 /* maximum size of the data portion */ #define IQS5XX_REC_TYPE_DATA 0x00 #define IQS5XX_REC_TYPE_EOF 0x01 @@ -97,14 +101,6 @@ struct iqs5xx_dev_id_info { u8 bl_status; } __packed; -struct iqs5xx_ihex_rec { - char start; - char len[2]; - char addr[4]; - char type[2]; - char data[2]; -} __packed; - struct iqs5xx_touch_data { __be16 abs_x; __be16 abs_y; @@ -355,7 +351,7 @@ static int iqs5xx_bl_open(struct i2c_client *client) } static int iqs5xx_bl_write(struct i2c_client *client, - u16 bl_addr, u8 *pmap_data, u16 pmap_len) + u16 bl_addr, const u8 *pmap_data, u16 pmap_len) { struct i2c_msg msg; int ret, i; @@ -394,7 +390,7 @@ msg_fail: } static int iqs5xx_bl_verify(struct i2c_client *client, - u16 bl_addr, u8 *pmap_data, u16 pmap_len) + u16 bl_addr, const u8 *pmap_data, u16 pmap_len) { struct i2c_msg msg; int ret, i; @@ -445,27 +441,21 @@ static int iqs5xx_set_state(struct i2c_client *client, u8 state) if (!iqs5xx->dev_id_info.bl_status) return 0; - mutex_lock(&iqs5xx->lock); + guard(mutex)(&iqs5xx->lock); /* * Addressing the device outside of a communication window prompts it * to assert the RDY output, so disable the interrupt line to prevent * the handler from servicing a false interrupt. */ - disable_irq(client->irq); + guard(disable_irq)(&client->irq); error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state); error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0); usleep_range(50, 100); - enable_irq(client->irq); - - mutex_unlock(&iqs5xx->lock); - if (error1) - return error1; - - return error2; + return error1 ?: error2; } static int iqs5xx_open(struct input_dev *input) @@ -702,15 +692,13 @@ static irqreturn_t iqs5xx_irq(int irq, void *data) static int iqs5xx_fw_file_parse(struct i2c_client *client, const char *fw_file, u8 *pmap) { - const struct firmware *fw; - struct iqs5xx_ihex_rec *rec; size_t pos = 0; int error, i; u16 rec_num = 1; u16 rec_addr; u8 rec_len, rec_type, rec_chksm, chksm; - u8 rec_hdr[IQS5XX_REC_HDR_LEN]; - u8 rec_data[IQS5XX_REC_LEN_MAX]; + u8 rec_hdr[IQS5XX_REC_HDR_SIZE]; + u8 rec_data[IQS5XX_REC_DATA_SIZE]; /* * Firmware exported from the vendor's configuration tool deviates from @@ -721,6 +709,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, * Because the ihex2fw tool tolerates neither (1) nor (2), the slightly * nonstandard ihex firmware is parsed directly by the driver. */ + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_file, &client->dev); if (error) { dev_err(&client->dev, "Failed to request firmware %s: %d\n", @@ -729,53 +718,55 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, } do { - if (pos + sizeof(*rec) > fw->size) { + if (pos + IQS5XX_REC_HDR_LEN_HEX > fw->size) { dev_err(&client->dev, "Insufficient firmware size\n"); - error = -EINVAL; - break; + return -EINVAL; } - rec = (struct iqs5xx_ihex_rec *)(fw->data + pos); - pos += sizeof(*rec); - if (rec->start != ':') { + if (fw->data[pos] != ':') { dev_err(&client->dev, "Invalid start at record %u\n", rec_num); - error = -EINVAL; - break; + return -EINVAL; } - error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr)); + /* Convert all 3 fields (length, address, and type) in one go */ + error = hex2bin(rec_hdr, &fw->data[pos + 1], sizeof(rec_hdr)); if (error) { dev_err(&client->dev, "Invalid header at record %u\n", rec_num); - break; + return error; } + pos += IQS5XX_REC_HDR_LEN_HEX; rec_len = *rec_hdr; rec_addr = get_unaligned_be16(rec_hdr + sizeof(rec_len)); rec_type = *(rec_hdr + sizeof(rec_len) + sizeof(rec_addr)); - if (pos + rec_len * 2 > fw->size) { + /* + * Check if we have enough data for the data portion of the + * record, as well as the checksum byte. Everything is doubled + * because data is in ASCII HEX and not binary format. + */ + if (pos + (rec_len + sizeof(rec_chksm)) * 2 > fw->size) { dev_err(&client->dev, "Insufficient firmware size\n"); - error = -EINVAL; - break; + return -EINVAL; } - pos += (rec_len * 2); - error = hex2bin(rec_data, rec->data, rec_len); + error = hex2bin(rec_data, &fw->data[pos], rec_len); if (error) { dev_err(&client->dev, "Invalid data at record %u\n", rec_num); - break; + return error; } + pos += rec_len * 2; - error = hex2bin(&rec_chksm, - rec->data + rec_len * 2, sizeof(rec_chksm)); + error = hex2bin(&rec_chksm, &fw->data[pos], sizeof(rec_chksm)); if (error) { dev_err(&client->dev, "Invalid checksum at record %u\n", rec_num); - break; + return error; } + pos += 2; chksm = 0; for (i = 0; i < sizeof(rec_hdr); i++) @@ -799,23 +790,22 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, dev_err(&client->dev, "Invalid address at record %u\n", rec_num); - error = -EINVAL; - } else { - memcpy(pmap + rec_addr - IQS5XX_CHKSM, - rec_data, rec_len); + return -EINVAL; } + + memcpy(pmap + rec_addr - IQS5XX_CHKSM, + rec_data, rec_len); break; + case IQS5XX_REC_TYPE_EOF: break; + default: dev_err(&client->dev, "Invalid type at record %u\n", rec_num); - error = -EINVAL; + return -EINVAL; } - if (error) - break; - rec_num++; while (pos < fw->size) { if (*(fw->data + pos) == ':') @@ -824,33 +814,13 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client, } } while (rec_type != IQS5XX_REC_TYPE_EOF); - release_firmware(fw); - - return error; + return 0; } -static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) +static int iqs5xx_update_firmware(struct iqs5xx_private *iqs5xx, const u8 *pmap) { - struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); - int error, error_init = 0; - u8 *pmap; - - pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL); - if (!pmap) - return -ENOMEM; - - error = iqs5xx_fw_file_parse(client, fw_file, pmap); - if (error) - goto err_kfree; - - mutex_lock(&iqs5xx->lock); - - /* - * Disable the interrupt line in case the first attempt(s) to enter the - * bootloader don't happen quickly enough, in which case the device may - * assert the RDY output until the next attempt. - */ - disable_irq(client->irq); + struct i2c_client *client = iqs5xx->client; + int error; iqs5xx->dev_id_info.bl_status = 0; @@ -858,22 +828,50 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) if (error) { error = iqs5xx_bl_open(client); if (error) - goto err_reset; + return error; } error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN); if (error) - goto err_reset; + return error; error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0); if (error) - goto err_reset; + return error; error = iqs5xx_bl_verify(client, IQS5XX_CSTM, pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN, IQS5XX_CSTM_LEN); + if (error) + return error; + + return 0; +} + +static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) +{ + struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); + int error, error_init = 0; + + u8 *pmap __free(kfree) = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL); + if (!pmap) + return -ENOMEM; + + error = iqs5xx_fw_file_parse(client, fw_file, pmap); + if (error) + return error; + + guard(mutex)(&iqs5xx->lock); + + /* + * Disable the interrupt line in case the first attempt(s) to enter the + * bootloader don't happen quickly enough, in which case the device may + * assert the RDY output until the next attempt. + */ + guard(disable_irq)(&client->irq); + + error = iqs5xx_update_firmware(iqs5xx, pmap); -err_reset: iqs5xx_reset(client); usleep_range(15000, 15100); @@ -881,14 +879,7 @@ err_reset: if (!iqs5xx->dev_id_info.bl_status) error_init = error_init ? : -EINVAL; - enable_irq(client->irq); - - mutex_unlock(&iqs5xx->lock); - -err_kfree: - kfree(pmap); - - return error ? : error_init; + return error ?: error_init; } static ssize_t fw_file_store(struct device *dev, @@ -984,38 +975,30 @@ static int iqs5xx_suspend(struct device *dev) { struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev); struct input_dev *input = iqs5xx->input; - int error = 0; if (!input || device_may_wakeup(dev)) - return error; - - mutex_lock(&input->mutex); + return 0; + guard(mutex)(&input->mutex); if (input_device_enabled(input)) - error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND); - - mutex_unlock(&input->mutex); + return iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND); - return error; + return 0; } static int iqs5xx_resume(struct device *dev) { struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev); struct input_dev *input = iqs5xx->input; - int error = 0; if (!input || device_may_wakeup(dev)) - return error; - - mutex_lock(&input->mutex); + return 0; + guard(mutex)(&input->mutex); if (input_device_enabled(input)) - error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME); - - mutex_unlock(&input->mutex); + return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME); - return error; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume); diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c index c5d447ee6f53..26e0b501c5fc 100644 --- a/drivers/input/touchscreen/iqs7211.c +++ b/drivers/input/touchscreen/iqs7211.c @@ -2060,19 +2060,16 @@ static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, for (i = 0; i < dev_desc->num_kp_events; i++) { const char *event_name = dev_desc->kp_events[i].name; - struct fwnode_handle *event_node; if (dev_desc->kp_events[i].reg_grp != reg_grp) continue; reg_field.mask |= dev_desc->kp_events[i].enable; - if (event_name) - event_node = fwnode_get_named_child_node(reg_grp_node, - event_name); - else - event_node = fwnode_handle_get(reg_grp_node); - + struct fwnode_handle *event_node __free(fwnode_handle) = + event_name ? fwnode_get_named_child_node(reg_grp_node, + event_name) : + fwnode_handle_get(reg_grp_node); if (!event_node) continue; @@ -2080,7 +2077,6 @@ static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, dev_desc->kp_events[i].reg_grp, dev_desc->kp_events[i].reg_key, &iqs7211->kp_code[i]); - fwnode_handle_put(event_node); if (error) return error; @@ -2496,19 +2492,15 @@ static int iqs7211_probe(struct i2c_client *client) for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) { const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp]; - struct fwnode_handle *reg_grp_node; - - if (reg_grp_name) - reg_grp_node = device_get_named_child_node(&client->dev, - reg_grp_name); - else - reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); + struct fwnode_handle *reg_grp_node __free(fwnode_handle) = + reg_grp_name ? device_get_named_child_node(&client->dev, + reg_grp_name) : + fwnode_handle_get(dev_fwnode(&client->dev)); if (!reg_grp_node) continue; error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp); - fwnode_handle_put(reg_grp_node); if (error) return error; } diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 9bad8b93c039..5de752a06b26 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -279,7 +279,7 @@ static int lpc32xx_ts_suspend(struct device *dev) * avoid calling the TSC stop and start functions as the TSC * isn't yet clocked. */ - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) { if (device_may_wakeup(dev)) @@ -288,8 +288,6 @@ static int lpc32xx_ts_suspend(struct device *dev) lpc32xx_stop_tsc(tsc); } - mutex_unlock(&input->mutex); - return 0; } @@ -298,7 +296,7 @@ static int lpc32xx_ts_resume(struct device *dev) struct lpc32xx_tsc *tsc = dev_get_drvdata(dev); struct input_dev *input = tsc->dev; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (input_device_enabled(input)) { if (device_may_wakeup(dev)) @@ -307,8 +305,6 @@ static int lpc32xx_ts_resume(struct device *dev) lpc32xx_setup_tsc(tsc); } - mutex_unlock(&input->mutex); - return 0; } diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c index 33635da85079..4b7e70a4c6d5 100644 --- a/drivers/input/touchscreen/mc13783_ts.c +++ b/drivers/input/touchscreen/mc13783_ts.c @@ -42,8 +42,6 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data) { struct mc13783_ts_priv *priv = data; - mc13xxx_irq_ack(priv->mc13xxx, irq); - /* * Kick off reading coordinates. Note that if work happens already * be queued for future execution (it rearms itself) it will not @@ -137,8 +135,6 @@ static int mc13783_ts_open(struct input_dev *dev) mc13xxx_lock(priv->mc13xxx); - mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS); - ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS, mc13783_ts_handler, MC13783_TS_NAME, priv); if (ret) @@ -172,7 +168,7 @@ static int __init mc13783_ts_probe(struct platform_device *pdev) struct input_dev *idev; int ret = -ENOMEM; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); idev = input_allocate_device(); if (!priv || !idev) goto err_free_mem; diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index a6946e3d8376..10fccf4e5bb1 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -881,8 +881,6 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, const u8 *data, int length, u16 buf_addr) { u8 cmd[6]; - u8 *data_buf; - u16 buf_offset; int ret; int error; @@ -895,7 +893,8 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, return -EINVAL; } - data_buf = kmalloc(2 + MIP4_BL_PACKET_SIZE, GFP_KERNEL); + u8 *data_buf __free(kfree) = kmalloc(2 + MIP4_BL_PACKET_SIZE, + GFP_KERNEL); if (!data_buf) return -ENOMEM; @@ -908,7 +907,7 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, error = ret < 0 ? ret : -EIO; dev_err(&ts->client->dev, "Failed to send write page address: %d\n", error); - goto out; + return error; } /* Size */ @@ -920,11 +919,11 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, error = ret < 0 ? ret : -EIO; dev_err(&ts->client->dev, "Failed to send write page size: %d\n", error); - goto out; + return error; } /* Data */ - for (buf_offset = 0; + for (int buf_offset = 0; buf_offset < length; buf_offset += MIP4_BL_PACKET_SIZE) { dev_dbg(&ts->client->dev, @@ -939,7 +938,7 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, dev_err(&ts->client->dev, "Failed to read chunk at %#04x (size %d): %d\n", buf_offset, MIP4_BL_PACKET_SIZE, error); - goto out; + return error; } } @@ -952,35 +951,21 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset, error = ret < 0 ? ret : -EIO; dev_err(&ts->client->dev, "Failed to send 'write' command: %d\n", error); - goto out; + return error; } /* Status */ error = mip4_bl_read_status(ts); + if (error) + return error; -out: - kfree(data_buf); - return error ? error : 0; + return 0; } static int mip4_bl_verify_page(struct mip4_ts *ts, int offset, const u8 *data, int length, int buf_addr) { u8 cmd[8]; - u8 *read_buf; - int buf_offset; - struct i2c_msg msg[] = { - { - .addr = ts->client->addr, - .flags = 0, - .buf = cmd, - .len = 2, - }, { - .addr = ts->client->addr, - .flags = I2C_M_RD, - .len = MIP4_BL_PACKET_SIZE, - }, - }; int ret; int error; @@ -1029,11 +1014,25 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset, return error; /* Read */ - msg[1].buf = read_buf = kmalloc(MIP4_BL_PACKET_SIZE, GFP_KERNEL); + u8 *read_buf __free(kfree) = kmalloc(MIP4_BL_PACKET_SIZE, GFP_KERNEL); if (!read_buf) return -ENOMEM; - for (buf_offset = 0; + struct i2c_msg msg[] = { + { + .addr = ts->client->addr, + .flags = 0, + .buf = cmd, + .len = 2, + }, { + .addr = ts->client->addr, + .flags = I2C_M_RD, + .buf = read_buf, + .len = MIP4_BL_PACKET_SIZE, + }, + }; + + for (int buf_offset = 0; buf_offset < length; buf_offset += MIP4_BL_PACKET_SIZE) { dev_dbg(&ts->client->dev, @@ -1046,7 +1045,7 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset, dev_err(&ts->client->dev, "Failed to read chunk at %#04x (size %d): %d\n", buf_offset, MIP4_BL_PACKET_SIZE, error); - break; + return error; } if (memcmp(&data[buf_offset], read_buf, MIP4_BL_PACKET_SIZE)) { @@ -1064,13 +1063,11 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset, DUMP_PREFIX_OFFSET, 16, 1, read_buf, MIP4_BL_PAGE_SIZE, false); #endif - error = -EINVAL; - break; + return -EINVAL; } } - kfree(read_buf); - return error ? error : 0; + return 0; } /* @@ -1290,9 +1287,9 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct mip4_ts *ts = i2c_get_clientdata(client); - const struct firmware *fw; int error; + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, ts->fw_name, dev); if (error) { dev_err(&ts->client->dev, @@ -1306,14 +1303,9 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev, * userspace opening and closing the device and also suspend/resume * transitions. */ - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); error = mip4_execute_fw_update(ts, fw); - - mutex_unlock(&ts->input->mutex); - - release_firmware(fw); - if (error) { dev_err(&ts->client->dev, "Firmware update failed: %d\n", error); @@ -1331,18 +1323,13 @@ static ssize_t mip4_sysfs_read_fw_version(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct mip4_ts *ts = i2c_get_clientdata(client); - size_t count; /* Take lock to prevent racing with firmware update */ - mutex_lock(&ts->input->mutex); - - count = sysfs_emit(buf, "%04X %04X %04X %04X\n", - ts->fw_version.boot, ts->fw_version.core, - ts->fw_version.app, ts->fw_version.param); + guard(mutex)(&ts->input->mutex); - mutex_unlock(&ts->input->mutex); - - return count; + return sysfs_emit(buf, "%04X %04X %04X %04X\n", + ts->fw_version.boot, ts->fw_version.core, + ts->fw_version.app, ts->fw_version.param); } static DEVICE_ATTR(fw_version, S_IRUGO, mip4_sysfs_read_fw_version, NULL); @@ -1353,21 +1340,16 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct mip4_ts *ts = i2c_get_clientdata(client); - size_t count; /* Take lock to prevent racing with firmware update */ - mutex_lock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); /* * product_name shows the name or version of the hardware * paired with current firmware in the chip. */ - count = sysfs_emit(buf, "%.*s\n", - (int)sizeof(ts->product_name), ts->product_name); - - mutex_unlock(&ts->input->mutex); - - return count; + return sysfs_emit(buf, "%.*s\n", + (int)sizeof(ts->product_name), ts->product_name); } static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL); @@ -1378,15 +1360,10 @@ static ssize_t mip4_sysfs_read_product_id(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct mip4_ts *ts = i2c_get_clientdata(client); - size_t count; - - mutex_lock(&ts->input->mutex); - count = sysfs_emit(buf, "%04X\n", ts->product_id); + guard(mutex)(&ts->input->mutex); - mutex_unlock(&ts->input->mutex); - - return count; + return sysfs_emit(buf, "%04X\n", ts->product_id); } static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL); @@ -1397,16 +1374,10 @@ static ssize_t mip4_sysfs_read_ic_name(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct mip4_ts *ts = i2c_get_clientdata(client); - size_t count; - - mutex_lock(&ts->input->mutex); - - count = sysfs_emit(buf, "%.*s\n", - (int)sizeof(ts->ic_name), ts->ic_name); - mutex_unlock(&ts->input->mutex); + guard(mutex)(&ts->input->mutex); - return count; + return sysfs_emit(buf, "%.*s\n", (int)sizeof(ts->ic_name), ts->ic_name); } static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL); @@ -1520,15 +1491,13 @@ static int mip4_suspend(struct device *dev) struct mip4_ts *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (device_may_wakeup(dev)) ts->wake_irq_enabled = enable_irq_wake(client->irq) == 0; else if (input_device_enabled(input)) mip4_disable(ts); - mutex_unlock(&input->mutex); - return 0; } @@ -1538,15 +1507,13 @@ static int mip4_resume(struct device *dev) struct mip4_ts *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (ts->wake_irq_enabled) disable_irq_wake(client->irq); else if (input_device_enabled(input)) mip4_enable(ts); - mutex_unlock(&input->mutex); - return 0; } @@ -1554,7 +1521,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume); #ifdef CONFIG_OF static const struct of_device_id mip4_of_match[] = { - { .compatible = "melfas,"MIP4_DEVICE_NAME, }, + { .compatible = "melfas,mip4_ts", }, { }, }; MODULE_DEVICE_TABLE(of, mip4_of_match); diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 7511a134e302..993d945dcd23 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -122,7 +122,7 @@ static int migor_ts_probe(struct i2c_client *client) struct input_dev *input; int error; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = kzalloc_obj(*priv); input = input_allocate_device(); if (!priv || !input) { dev_err(&client->dev, "failed to allocate memory\n"); diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c deleted file mode 100644 index 753d9cc1de1f..000000000000 --- a/drivers/input/touchscreen/mk712.c +++ /dev/null @@ -1,215 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ICS MK712 touchscreen controller driver - * - * Copyright (c) 1999-2002 Transmeta Corporation - * Copyright (c) 2005 Rick Koch <n1gp@hotmail.com> - * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz> - */ - - -/* - * This driver supports the ICS MicroClock MK712 TouchScreen controller, - * found in Gateway AOL Connected Touchpad computers. - * - * Documentation for ICS MK712 can be found at: - * https://www.idt.com/general-parts/mk712-touch-screen-controller - */ - -/* - * 1999-12-18: original version, Daniel Quinlan - * 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll - * to use queue_empty, Nathan Laredo - * 1999-12-20: improved random point rejection, Nathan Laredo - * 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed - * queue code, added module options, other fixes, Daniel Quinlan - * 2002-03-15: Clean up for kernel merge <alan@redhat.com> - * Fixed multi open race, fixed memory checks, fixed resource - * allocation, fixed close/powerdown bug, switched to new init - * 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch - * 2005-02-05: Rewritten for the input layer, Vojtech Pavlik - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <asm/io.h> - -MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>"); -MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver"); -MODULE_LICENSE("GPL"); - -static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */ -module_param_hw_named(io, mk712_io, uint, ioport, 0); -MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller"); - -static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */ -module_param_hw_named(irq, mk712_irq, uint, irq, 0); -MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller"); - -/* eight 8-bit registers */ -#define MK712_STATUS 0 -#define MK712_X 2 -#define MK712_Y 4 -#define MK712_CONTROL 6 -#define MK712_RATE 7 - -/* status */ -#define MK712_STATUS_TOUCH 0x10 -#define MK712_CONVERSION_COMPLETE 0x80 - -/* control */ -#define MK712_ENABLE_INT 0x01 -#define MK712_INT_ON_CONVERSION_COMPLETE 0x02 -#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04 -#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10 -#define MK712_READ_ONE_POINT 0x20 -#define MK712_POWERUP 0x40 - -static struct input_dev *mk712_dev; -static DEFINE_SPINLOCK(mk712_lock); - -static irqreturn_t mk712_interrupt(int irq, void *dev_id) -{ - unsigned char status; - static int debounce = 1; - static unsigned short last_x; - static unsigned short last_y; - - spin_lock(&mk712_lock); - - status = inb(mk712_io + MK712_STATUS); - - if (~status & MK712_CONVERSION_COMPLETE) { - debounce = 1; - goto end; - } - - if (~status & MK712_STATUS_TOUCH) { - debounce = 1; - input_report_key(mk712_dev, BTN_TOUCH, 0); - goto end; - } - - if (debounce) { - debounce = 0; - goto end; - } - - input_report_key(mk712_dev, BTN_TOUCH, 1); - input_report_abs(mk712_dev, ABS_X, last_x); - input_report_abs(mk712_dev, ABS_Y, last_y); - - end: - last_x = inw(mk712_io + MK712_X) & 0x0fff; - last_y = inw(mk712_io + MK712_Y) & 0x0fff; - input_sync(mk712_dev); - spin_unlock(&mk712_lock); - return IRQ_HANDLED; -} - -static int mk712_open(struct input_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&mk712_lock, flags); - - outb(0, mk712_io + MK712_CONTROL); /* Reset */ - - outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE | - MK712_INT_ON_CHANGE_IN_TOUCH_STATUS | - MK712_ENABLE_PERIODIC_CONVERSIONS | - MK712_POWERUP, mk712_io + MK712_CONTROL); - - outb(10, mk712_io + MK712_RATE); /* 187 points per second */ - - spin_unlock_irqrestore(&mk712_lock, flags); - - return 0; -} - -static void mk712_close(struct input_dev *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&mk712_lock, flags); - - outb(0, mk712_io + MK712_CONTROL); - - spin_unlock_irqrestore(&mk712_lock, flags); -} - -static int __init mk712_init(void) -{ - int err; - - if (!request_region(mk712_io, 8, "mk712")) { - printk(KERN_WARNING "mk712: unable to get IO region\n"); - return -ENODEV; - } - - outb(0, mk712_io + MK712_CONTROL); - - if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */ - (inw(mk712_io + MK712_Y) & 0xf000) || - (inw(mk712_io + MK712_STATUS) & 0xf333)) { - printk(KERN_WARNING "mk712: device not present\n"); - err = -ENODEV; - goto fail1; - } - - mk712_dev = input_allocate_device(); - if (!mk712_dev) { - printk(KERN_ERR "mk712: not enough memory\n"); - err = -ENOMEM; - goto fail1; - } - - mk712_dev->name = "ICS MicroClock MK712 TouchScreen"; - mk712_dev->phys = "isa0260/input0"; - mk712_dev->id.bustype = BUS_ISA; - mk712_dev->id.vendor = 0x0005; - mk712_dev->id.product = 0x0001; - mk712_dev->id.version = 0x0100; - - mk712_dev->open = mk712_open; - mk712_dev->close = mk712_close; - - mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0); - input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0); - - if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) { - printk(KERN_WARNING "mk712: unable to get IRQ\n"); - err = -EBUSY; - goto fail1; - } - - err = input_register_device(mk712_dev); - if (err) - goto fail2; - - return 0; - - fail2: free_irq(mk712_irq, mk712_dev); - fail1: input_free_device(mk712_dev); - release_region(mk712_io, 8); - return err; -} - -static void __exit mk712_exit(void) -{ - input_unregister_device(mk712_dev); - free_irq(mk712_irq, mk712_dev); - release_region(mk712_io, 8); -} - -module_init(mk712_init); -module_exit(mk712_exit); diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 9f947044c4d9..af462086a65c 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -216,20 +216,12 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id) { struct mms114_data *data = dev_id; struct i2c_client *client = data->client; - struct input_dev *input_dev = data->input_dev; struct mms114_touch touch[MMS114_MAX_TOUCH]; int packet_size; int touch_size; int index; int error; - mutex_lock(&input_dev->mutex); - if (!input_device_enabled(input_dev)) { - mutex_unlock(&input_dev->mutex); - goto out; - } - mutex_unlock(&input_dev->mutex); - packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE); if (packet_size <= 0) goto out; @@ -646,10 +638,10 @@ static int mms114_suspend(struct device *dev) input_mt_report_pointer_emulation(input_dev, true); input_sync(input_dev); - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); + if (input_device_enabled(input_dev)) mms114_stop(data); - mutex_unlock(&input_dev->mutex); return 0; } @@ -661,15 +653,13 @@ static int mms114_resume(struct device *dev) struct input_dev *input_dev = data->input_dev; int error; - mutex_lock(&input_dev->mutex); + guard(mutex)(&input_dev->mutex); + if (input_device_enabled(input_dev)) { error = mms114_start(data); - if (error < 0) { - mutex_unlock(&input_dev->mutex); + if (error) return error; - } } - mutex_unlock(&input_dev->mutex); return 0; } diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c index a38af3fee34a..240d2eebf1c9 100644 --- a/drivers/input/touchscreen/msg2638.c +++ b/drivers/input/touchscreen/msg2638.c @@ -446,13 +446,11 @@ static int msg2638_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client); - mutex_lock(&msg2638->input_dev->mutex); + guard(mutex)(&msg2638->input_dev->mutex); if (input_device_enabled(msg2638->input_dev)) msg2638_stop(msg2638); - mutex_unlock(&msg2638->input_dev->mutex); - return 0; } @@ -460,16 +458,17 @@ static int msg2638_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client); - int ret = 0; - - mutex_lock(&msg2638->input_dev->mutex); + int error; - if (input_device_enabled(msg2638->input_dev)) - ret = msg2638_start(msg2638); + guard(mutex)(&msg2638->input_dev->mutex); - mutex_unlock(&msg2638->input_dev->mutex); + if (input_device_enabled(msg2638->input_dev)) { + error = msg2638_start(msg2638); + if (error) + return error; + } - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume); diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c index eefae96a2d40..cc2d206d2f3d 100644 --- a/drivers/input/touchscreen/mtouch.c +++ b/drivers/input/touchscreen/mtouch.c @@ -128,7 +128,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - mtouch = kzalloc(sizeof(*mtouch), GFP_KERNEL); + mtouch = kzalloc_obj(*mtouch); input_dev = input_allocate_device(); if (!mtouch || !input_dev) { err = -ENOMEM; @@ -137,7 +137,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv) mtouch->serio = serio; mtouch->dev = input_dev; - snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys); + scnprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys); input_dev->name = "MicroTouch Serial TouchScreen"; input_dev->phys = mtouch->phys; diff --git a/drivers/input/touchscreen/mxs-lradc-ts.c b/drivers/input/touchscreen/mxs-lradc-ts.c index 9e36fee38d61..137ab3b60f2d 100644 --- a/drivers/input/touchscreen/mxs-lradc-ts.c +++ b/drivers/input/touchscreen/mxs-lradc-ts.c @@ -500,15 +500,14 @@ static irqreturn_t mxs_lradc_ts_handle_irq(int irq, void *data) LRADC_CTRL1_TOUCH_DETECT_IRQ | LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2); - unsigned long flags; if (!(reg & mxs_lradc_irq_mask(lradc))) return IRQ_NONE; if (reg & ts_irq_mask) { - spin_lock_irqsave(&ts->lock, flags); - mxs_lradc_handle_touch(ts); - spin_unlock_irqrestore(&ts->lock, flags); + scoped_guard(spinlock_irqsave, &ts->lock) { + mxs_lradc_handle_touch(ts); + } /* Make sure we don't clear the next conversion's interrupt. */ clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) | LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2)); diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 44b58e0dc1ad..708bfb933ddd 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -27,7 +27,6 @@ #define NVT_TS_PARAMS_MAX_TOUCH 0x09 #define NVT_TS_PARAMS_MAX_BUTTONS 0x0a #define NVT_TS_PARAMS_IRQ_TYPE 0x0b -#define NVT_TS_PARAMS_WAKE_TYPE 0x0c #define NVT_TS_PARAMS_CHIP_ID 0x0e #define NVT_TS_PARAMS_SIZE 0x0f @@ -49,7 +48,6 @@ static const int nvt_ts_irq_type[4] = { }; struct nvt_ts_i2c_chip_data { - u8 wake_type; u8 chip_id; }; @@ -172,10 +170,10 @@ static int nvt_ts_suspend(struct device *dev) { struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->input->mutex); + guard(mutex)(&data->input->mutex); + if (input_device_enabled(data->input)) nvt_ts_stop(data->input); - mutex_unlock(&data->input->mutex); return 0; } @@ -184,10 +182,10 @@ static int nvt_ts_resume(struct device *dev) { struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); - mutex_lock(&data->input->mutex); + guard(mutex)(&data->input->mutex); + if (input_device_enabled(data->input)) nvt_ts_start(data->input); - mutex_unlock(&data->input->mutex); return 0; } @@ -261,7 +259,6 @@ static int nvt_ts_probe(struct i2c_client *client) if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE || data->max_touches > NVT_TS_MAX_TOUCHES || irq_type >= ARRAY_SIZE(nvt_ts_irq_type) || - data->buf[NVT_TS_PARAMS_WAKE_TYPE] != chip->wake_type || data->buf[NVT_TS_PARAMS_CHIP_ID] != chip->chip_id) { dev_err(dev, "Unsupported touchscreen parameters: %*ph\n", NVT_TS_PARAMS_SIZE, data->buf); @@ -314,12 +311,10 @@ static int nvt_ts_probe(struct i2c_client *client) } static const struct nvt_ts_i2c_chip_data nvt_nt11205_ts_data = { - .wake_type = 0x05, .chip_id = 0x05, }; static const struct nvt_ts_i2c_chip_data nvt_nt36672a_ts_data = { - .wake_type = 0x01, .chip_id = 0x08, }; diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c index 083206a3457b..7b89eb74b9de 100644 --- a/drivers/input/touchscreen/pcap_ts.c +++ b/drivers/input/touchscreen/pcap_ts.c @@ -138,7 +138,7 @@ static int pcap_ts_probe(struct platform_device *pdev) struct pcap_ts *pcap_ts; int err = -ENOMEM; - pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL); + pcap_ts = kzalloc_obj(*pcap_ts); if (!pcap_ts) return err; diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c index 95adede26703..4b57b6664e37 100644 --- a/drivers/input/touchscreen/penmount.c +++ b/drivers/input/touchscreen/penmount.c @@ -199,7 +199,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) int max_x, max_y; int err; - pm = kzalloc(sizeof(*pm), GFP_KERNEL); + pm = kzalloc_obj(*pm); input_dev = input_allocate_device(); if (!pm || !input_dev) { err = -ENOMEM; @@ -208,7 +208,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv) pm->serio = serio; pm->dev = input_dev; - snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); + scnprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys); pm->maxcontacts = 1; input_dev->name = "PenMount Serial TouchScreen"; diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index dad5786e82a4..c6b3615c8775 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -410,26 +410,25 @@ static int pixcir_i2c_ts_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - int ret = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (device_may_wakeup(&client->dev)) { if (!input_device_enabled(input)) { - ret = pixcir_start(ts); - if (ret) { + error = pixcir_start(ts); + if (error) { dev_err(dev, "Failed to start\n"); - goto unlock; + return error; } } } else if (input_device_enabled(input)) { - ret = pixcir_stop(ts); + error = pixcir_stop(ts); + if (error) + return error; } -unlock: - mutex_unlock(&input->mutex); - - return ret; + return 0; } static int pixcir_i2c_ts_resume(struct device *dev) @@ -437,26 +436,25 @@ static int pixcir_i2c_ts_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); struct input_dev *input = ts->input; - int ret = 0; + int error; - mutex_lock(&input->mutex); + guard(mutex)(&input->mutex); if (device_may_wakeup(&client->dev)) { if (!input_device_enabled(input)) { - ret = pixcir_stop(ts); - if (ret) { + error = pixcir_stop(ts); + if (error) { dev_err(dev, "Failed to stop\n"); - goto unlock; + return error; } } } else if (input_device_enabled(input)) { - ret = pixcir_start(ts); + error = pixcir_start(ts); + if (error) + return error; } -unlock: - mutex_unlock(&input->mutex); - - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index f975b53e8825..f2d33ad86fd2 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -169,10 +169,9 @@ static int raydium_i2c_send(struct i2c_client *client, { int tries = 0; int error; - u8 *tx_buf; u8 reg_addr = addr & 0xff; - tx_buf = kmalloc(len + 1, GFP_KERNEL); + u8 *tx_buf __free(kfree) = kmalloc(len + 1, GFP_KERNEL); if (!tx_buf) return -ENOMEM; @@ -210,14 +209,12 @@ static int raydium_i2c_send(struct i2c_client *client, error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer)); if (likely(!error)) - goto out; + return 0; msleep(RM_RETRY_DELAY_MS); } while (++tries < RM_MAX_RETRIES); dev_err(&client->dev, "%s failed: %d\n", __func__, error); -out: - kfree(tx_buf); return error; } @@ -815,21 +812,21 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts, static int raydium_i2c_fw_update(struct raydium_data *ts) { struct i2c_client *client = ts->client; - const struct firmware *fw = NULL; - char *fw_file; int error; - fw_file = kasprintf(GFP_KERNEL, "raydium_%#04x.fw", - le32_to_cpu(ts->info.hw_ver)); + const char *fw_file __free(kfree) = + kasprintf(GFP_KERNEL, "raydium_%#04x.fw", + le32_to_cpu(ts->info.hw_ver)); if (!fw_file) return -ENOMEM; dev_dbg(&client->dev, "firmware name: %s\n", fw_file); + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_file, &client->dev); if (error) { dev_err(&client->dev, "Unable to open firmware %s\n", fw_file); - goto out_free_fw_file; + return error; } disable_irq(client->irq); @@ -856,11 +853,6 @@ out_enable_irq: enable_irq(client->irq); msleep(100); - release_firmware(fw); - -out_free_fw_file: - kfree(fw_file); - return error; } @@ -965,15 +957,12 @@ static ssize_t raydium_i2c_update_fw_store(struct device *dev, struct raydium_data *ts = i2c_get_clientdata(client); int error; - error = mutex_lock_interruptible(&ts->sysfs_mutex); - if (error) - return error; - - error = raydium_i2c_fw_update(ts); - - mutex_unlock(&ts->sysfs_mutex); + scoped_guard(mutex_intr, &ts->sysfs_mutex) { + error = raydium_i2c_fw_update(ts); + return error ?: count; + } - return error ?: count; + return -EINTR; } static ssize_t raydium_i2c_calibrate_store(struct device *dev, @@ -985,17 +974,20 @@ static ssize_t raydium_i2c_calibrate_store(struct device *dev, static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E }; int error; - error = mutex_lock_interruptible(&ts->sysfs_mutex); - if (error) - return error; + scoped_guard(mutex_intr, &ts->sysfs_mutex) { + error = raydium_i2c_write_object(client, + cal_cmd, sizeof(cal_cmd), + RAYDIUM_WAIT_READY); + if (error) { + dev_err(&client->dev, + "calibrate command failed: %d\n", error); + return error; + } - error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd), - RAYDIUM_WAIT_READY); - if (error) - dev_err(&client->dev, "calibrate command failed: %d\n", error); + return count; + } - mutex_unlock(&ts->sysfs_mutex); - return error ?: count; + return -EINTR; } static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 6475084aee1b..9b266927b7fe 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -15,6 +15,7 @@ #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/mt.h> +#include <linux/input/touch-overlay.h> #include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/module.h> @@ -22,10 +23,14 @@ #include <linux/pm_qos.h> #include <linux/slab.h> #include <linux/types.h> +#include <asm/byteorder.h> #define ST1232_TS_NAME "st1232-ts" #define ST1633_TS_NAME "st1633-ts" +#define REG_FIRMWARE_VERSION 0x00 +#define REG_FIRMWARE_REVISION_3 0x0C + #define REG_STATUS 0x01 /* Device Status | Error Code */ #define STATUS_NORMAL 0x00 @@ -57,10 +62,41 @@ struct st1232_ts_data { struct dev_pm_qos_request low_latency_req; struct gpio_desc *reset_gpio; const struct st_chip_info *chip_info; + struct list_head touch_overlay_list; int read_buf_len; u8 *read_buf; + u8 fw_version; + u32 fw_revision; }; +static ssize_t fw_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct st1232_ts_data *st1232_ts = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%u\n", st1232_ts->fw_version); +} + +static ssize_t fw_revision_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct st1232_ts_data *st1232_ts = i2c_get_clientdata(client); + + return sysfs_emit(buf, "%08x\n", st1232_ts->fw_revision); +} + +static DEVICE_ATTR_RO(fw_version); +static DEVICE_ATTR_RO(fw_revision); + +static struct attribute *st1232_attrs[] = { + &dev_attr_fw_version.attr, + &dev_attr_fw_revision.attr, + NULL, +}; +ATTRIBUTE_GROUPS(st1232); + static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg, unsigned int n) { @@ -108,6 +144,26 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts) return -ENXIO; } +static int st1232_ts_read_fw_version(struct st1232_ts_data *ts, + u8 *fw_version, u32 *fw_revision) +{ + int error; + + /* select firmware version register */ + error = st1232_ts_read_data(ts, REG_FIRMWARE_VERSION, 1); + if (error) + return error; + *fw_version = ts->read_buf[0]; + + /* select firmware revision register */ + error = st1232_ts_read_data(ts, REG_FIRMWARE_REVISION_3, 4); + if (error) + return error; + *fw_revision = le32_to_cpup((__le32 *)ts->read_buf); + + return 0; +} + static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x, u16 *max_y) { @@ -156,6 +212,10 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts) input_mt_assign_slots(input, slots, pos, n_contacts, 0); for (i = 0; i < n_contacts; i++) { + if (touch_overlay_process_contact(&ts->touch_overlay_list, + input, &pos[i], slots[i])) + continue; + input_mt_slot(input, slots[i]); input_mt_report_slot_state(input, MT_TOOL_FINGER, true); input_report_abs(input, ABS_MT_POSITION_X, pos[i].x); @@ -164,6 +224,7 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts) input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]); } + touch_overlay_sync_frame(&ts->touch_overlay_list, input); input_mt_sync_frame(input); input_sync(input); @@ -292,18 +353,40 @@ static int st1232_ts_probe(struct i2c_client *client) if (error) return error; - /* Read resolution from the chip */ - error = st1232_ts_read_resolution(ts, &max_x, &max_y); + /* Read firmware version from the chip */ + error = st1232_ts_read_fw_version(ts, &ts->fw_version, &ts->fw_revision); if (error) { dev_err(&client->dev, - "Failed to read resolution: %d\n", error); + "Failed to read firmware version: %d\n", error); return error; } + dev_dbg(&client->dev, "Detected firmware version %u, rev %08x\n", + ts->fw_version, ts->fw_revision); if (ts->chip_info->have_z) input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, ts->chip_info->max_area, 0, 0); + /* map overlay objects if defined in the device tree */ + INIT_LIST_HEAD(&ts->touch_overlay_list); + error = touch_overlay_map(&ts->touch_overlay_list, input_dev); + if (error) + return error; + + if (touch_overlay_mapped_touchscreen(&ts->touch_overlay_list)) { + /* Read resolution from the overlay touchscreen if defined */ + touch_overlay_get_touchscreen_abs(&ts->touch_overlay_list, + &max_x, &max_y); + } else { + /* 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; + } + } + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0); input_set_abs_params(input_dev, ABS_MT_POSITION_Y, @@ -389,6 +472,7 @@ static struct i2c_driver st1232_ts_driver = { .driver = { .name = ST1232_TS_NAME, .of_match_table = st1232_ts_dt_ids, + .dev_groups = st1232_groups, .probe_type = PROBE_PREFER_ASYNCHRONOUS, .pm = pm_sleep_ptr(&st1232_ts_pm_ops), }, diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index 119cd26851cf..8af87d0b6eb6 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -120,7 +120,7 @@ static int stmfts_brightness_set(struct led_classdev *led_cdev, err = regulator_enable(sdata->ledvdd); if (err) { dev_warn(&sdata->client->dev, - "failed to disable ledvdd regulator: %d\n", + "failed to enable ledvdd regulator: %d\n", err); return err; } @@ -141,7 +141,7 @@ static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev) /* * We can't simply use i2c_smbus_read_i2c_block_data because we - * need to read more than 255 bytes ( + * need to read 256 bytes, which exceeds the 255-byte SMBus block limit. */ static int stmfts_read_events(struct stmfts_data *sdata) { @@ -302,7 +302,7 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev) struct stmfts_data *sdata = dev; int err; - mutex_lock(&sdata->mutex); + guard(mutex)(&sdata->mutex); err = stmfts_read_events(sdata); if (unlikely(err)) @@ -311,7 +311,6 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev) else stmfts_parse_events(sdata); - mutex_unlock(&sdata->mutex); return IRQ_HANDLED; } @@ -347,17 +346,17 @@ static int stmfts_input_open(struct input_dev *dev) return err; } - mutex_lock(&sdata->mutex); - sdata->running = true; + scoped_guard(mutex, &sdata->mutex) { + sdata->running = true; - if (sdata->hover_enabled) { - err = i2c_smbus_write_byte(sdata->client, - STMFTS_SS_HOVER_SENSE_ON); - if (err) - dev_warn(&sdata->client->dev, - "failed to enable hover\n"); + if (sdata->hover_enabled) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_SS_HOVER_SENSE_ON); + if (err) + dev_warn(&sdata->client->dev, + "failed to enable hover\n"); + } } - mutex_unlock(&sdata->mutex); if (sdata->use_key) { err = i2c_smbus_write_byte(sdata->client, @@ -381,18 +380,17 @@ static void stmfts_input_close(struct input_dev *dev) dev_warn(&sdata->client->dev, "failed to disable touchscreen: %d\n", err); - mutex_lock(&sdata->mutex); + scoped_guard(mutex, &sdata->mutex) { + sdata->running = false; - sdata->running = false; - - if (sdata->hover_enabled) { - err = i2c_smbus_write_byte(sdata->client, - STMFTS_SS_HOVER_SENSE_OFF); - if (err) - dev_warn(&sdata->client->dev, - "failed to disable hover: %d\n", err); + if (sdata->hover_enabled) { + err = i2c_smbus_write_byte(sdata->client, + STMFTS_SS_HOVER_SENSE_OFF); + if (err) + dev_warn(&sdata->client->dev, + "failed to disable hover: %d\n", err); + } } - mutex_unlock(&sdata->mutex); if (sdata->use_key) { err = i2c_smbus_write_byte(sdata->client, @@ -410,7 +408,7 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%#x\n", sdata->chip_id); + return sysfs_emit(buf, "%#x\n", sdata->chip_id); } static ssize_t stmfts_sysfs_chip_version(struct device *dev, @@ -418,7 +416,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", sdata->chip_ver); + return sysfs_emit(buf, "%u\n", sdata->chip_ver); } static ssize_t stmfts_sysfs_fw_ver(struct device *dev, @@ -426,7 +424,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", sdata->fw_ver); + return sysfs_emit(buf, "%u\n", sdata->fw_ver); } static ssize_t stmfts_sysfs_config_id(struct device *dev, @@ -434,7 +432,7 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%#x\n", sdata->config_id); + return sysfs_emit(buf, "%#x\n", sdata->config_id); } static ssize_t stmfts_sysfs_config_version(struct device *dev, @@ -442,7 +440,7 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", sdata->config_ver); + return sysfs_emit(buf, "%u\n", sdata->config_ver); } static ssize_t stmfts_sysfs_read_status(struct device *dev, @@ -457,7 +455,7 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev, if (err) return err; - return sprintf(buf, "%#02x\n", status[0]); + return sysfs_emit(buf, "%#02x\n", status[0]); } static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, @@ -465,7 +463,7 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); - return sprintf(buf, "%u\n", sdata->hover_enabled); + return sysfs_emit(buf, "%u\n", sdata->hover_enabled); } static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, @@ -474,26 +472,27 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, { struct stmfts_data *sdata = dev_get_drvdata(dev); unsigned long value; - int err = 0; + bool hover; + int err; if (kstrtoul(buf, 0, &value)) return -EINVAL; - mutex_lock(&sdata->mutex); + hover = !!value; - if (value && sdata->hover_enabled) - goto out; + guard(mutex)(&sdata->mutex); - if (sdata->running) - err = i2c_smbus_write_byte(sdata->client, + if (hover != sdata->hover_enabled) { + if (sdata->running) { + err = i2c_smbus_write_byte(sdata->client, value ? STMFTS_SS_HOVER_SENSE_ON : STMFTS_SS_HOVER_SENSE_OFF); + if (err) + return err; + } - if (!err) - sdata->hover_enabled = !!value; - -out: - mutex_unlock(&sdata->mutex); + sdata->hover_enabled = hover; + } return len; } @@ -594,9 +593,6 @@ static void stmfts_power_off(void *data) sdata->regulators); } -/* This function is void because I don't want to prevent using the touch key - * only because the LEDs don't get registered - */ static int stmfts_enable_led(struct stmfts_data *sdata) { int err; diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index a94a1997f96b..af0fb38bcfdc 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -366,12 +366,7 @@ static struct platform_driver stmpe_ts_driver = { }; module_platform_driver(stmpe_ts_driver); -static const struct of_device_id stmpe_ts_ids[] = { - { .compatible = "st,stmpe-ts", }, - { }, -}; -MODULE_DEVICE_TABLE(of, stmpe_ts_ids); - +MODULE_ALIAS("platform:stmpe-ts"); MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>"); MODULE_DESCRIPTION("STMPEXXX touchscreen driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 8365a2ac6fce..fe63d53d56db 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -538,15 +538,15 @@ static void sur40_process_video(struct sur40_state *sur40) return; /* get a new buffer from the list */ - spin_lock(&sur40->qlock); - if (list_empty(&sur40->buf_list)) { - dev_dbg(sur40->dev, "buffer queue empty\n"); - spin_unlock(&sur40->qlock); - return; + scoped_guard(spinlock, &sur40->qlock) { + if (list_empty(&sur40->buf_list)) { + dev_dbg(sur40->dev, "buffer queue empty\n"); + return; + } + new_buf = list_first_entry(&sur40->buf_list, + struct sur40_buffer, list); + list_del(&new_buf->list); } - new_buf = list_entry(sur40->buf_list.next, struct sur40_buffer, list); - list_del(&new_buf->list); - spin_unlock(&sur40->qlock); dev_dbg(sur40->dev, "buffer acquired\n"); @@ -672,7 +672,7 @@ static int sur40_probe(struct usb_interface *interface, return -ENODEV; /* Allocate memory for our device state and initialize it. */ - sur40 = kzalloc(sizeof(*sur40), GFP_KERNEL); + sur40 = kzalloc_obj(*sur40); if (!sur40) return -ENOMEM; @@ -888,9 +888,8 @@ static void sur40_buffer_queue(struct vb2_buffer *vb) struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue); struct sur40_buffer *buf = (struct sur40_buffer *)vb; - spin_lock(&sur40->qlock); + guard(spinlock)(&sur40->qlock); list_add_tail(&buf->list, &sur40->buf_list); - spin_unlock(&sur40->qlock); } static void return_all_buffers(struct sur40_state *sur40, @@ -898,12 +897,12 @@ static void return_all_buffers(struct sur40_state *sur40, { struct sur40_buffer *buf, *node; - spin_lock(&sur40->qlock); + guard(spinlock)(&sur40->qlock); + list_for_each_entry_safe(buf, node, &sur40->buf_list, list) { vb2_buffer_done(&buf->vb.vb2_buf, state); list_del(&buf->list); } - spin_unlock(&sur40->qlock); } /* @@ -1108,8 +1107,6 @@ static const struct vb2_ops sur40_queue_ops = { .buf_queue = sur40_buffer_queue, .start_streaming = sur40_start_streaming, .stop_streaming = sur40_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, }; static const struct vb2_queue sur40_queue = { diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index f5c5881cef6b..0d92aaeea3e0 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -116,13 +116,12 @@ static inline void sx865x_penrelease(struct sx8654 *ts) static void sx865x_penrelease_timer_handler(struct timer_list *t) { - struct sx8654 *ts = from_timer(ts, t, timer); - unsigned long flags; + struct sx8654 *ts = timer_container_of(ts, t, timer); - spin_lock_irqsave(&ts->lock, flags); - sx865x_penrelease(ts); - spin_unlock_irqrestore(&ts->lock, flags); dev_dbg(&ts->client->dev, "penrelease by timer\n"); + + guard(spinlock_irqsave)(&ts->lock); + sx865x_penrelease(ts); } static irqreturn_t sx8650_irq(int irq, void *handle) @@ -130,7 +129,6 @@ static irqreturn_t sx8650_irq(int irq, void *handle) struct sx8654 *ts = handle; struct device *dev = &ts->client->dev; int len, i; - unsigned long flags; u8 stat; u16 x, y; u16 ch; @@ -153,7 +151,7 @@ static irqreturn_t sx8650_irq(int irq, void *handle) return IRQ_HANDLED; } - spin_lock_irqsave(&ts->lock, flags); + guard(spinlock_irqsave)(&ts->lock); x = 0; y = 0; @@ -184,7 +182,6 @@ static irqreturn_t sx8650_irq(int irq, void *handle) dev_dbg(dev, "point(%4d,%4d)\n", x, y); mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT); - spin_unlock_irqrestore(&ts->lock, flags); return IRQ_HANDLED; } @@ -290,7 +287,7 @@ static void sx8654_close(struct input_dev *dev) disable_irq(client->irq); if (!sx8654->data->has_irq_penrelease) - del_timer_sync(&sx8654->timer); + timer_delete_sync(&sx8654->timer); /* enable manual mode mode */ error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual); @@ -394,9 +391,13 @@ static int sx8654_probe(struct i2c_client *client) return error; } + /* + * Start with the interrupt disabled, it will be enabled in + * sx8654_open(). + */ error = devm_request_threaded_irq(&client->dev, client->irq, NULL, sx8654->data->irqh, - IRQF_ONESHOT, + IRQF_ONESHOT | IRQF_NO_AUTOEN, client->name, sx8654); if (error) { dev_err(&client->dev, @@ -405,9 +406,6 @@ static int sx8654_probe(struct i2c_client *client) return error; } - /* Disable the IRQ, we'll enable it in sx8654_open() */ - disable_irq(client->irq); - error = input_register_device(sx8654->input); if (error) return error; diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 93d659ff90aa..623546e80668 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -85,7 +85,7 @@ static int titsc_config_wires(struct titsc *ts_dev) wire_order[i] = ts_dev->config_inp[i] & 0x0F; if (WARN_ON(analog_line[i] > 7)) return -EINVAL; - if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins))) + if (WARN_ON(wire_order[i] >= ARRAY_SIZE(config_pins))) return -EINVAL; } @@ -389,6 +389,10 @@ static int titsc_parse_dt(struct platform_device *pdev, dev_warn(&pdev->dev, "invalid co-ordinate readouts, resetting it to 5\n"); ts_dev->coordinate_readouts = 5; + } else if (ts_dev->coordinate_readouts > 6) { + dev_warn(&pdev->dev, + "co-ordinate readouts too large, limiting to 6\n"); + ts_dev->coordinate_readouts = 6; } err = of_property_read_u32(node, "ti,charge-delay", @@ -418,7 +422,7 @@ static int titsc_probe(struct platform_device *pdev) int err; /* Allocate memory for device */ - ts_dev = kzalloc(sizeof(*ts_dev), GFP_KERNEL); + ts_dev = kzalloc_obj(*ts_dev); input_dev = input_allocate_device(); if (!ts_dev || !input_dev) { dev_err(&pdev->dev, "failed to allocate memory.\n"); diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c index c2718350815c..6d4a1acf57c9 100644 --- a/drivers/input/touchscreen/touchit213.c +++ b/drivers/input/touchscreen/touchit213.c @@ -139,7 +139,7 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - touchit213 = kzalloc(sizeof(*touchit213), GFP_KERNEL); + touchit213 = kzalloc_obj(*touchit213); input_dev = input_allocate_device(); if (!touchit213 || !input_dev) { err = -ENOMEM; @@ -148,8 +148,8 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv) touchit213->serio = serio; touchit213->dev = input_dev; - snprintf(touchit213->phys, sizeof(touchit213->phys), - "%s/input0", serio->phys); + scnprintf(touchit213->phys, sizeof(touchit213->phys), + "%s/input0", serio->phys); input_dev->name = "Sahara Touch-iT213 Serial TouchScreen"; input_dev->phys = touchit213->phys; diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c index 30ba97bd00a1..d7fdf201e4d1 100644 --- a/drivers/input/touchscreen/touchright.c +++ b/drivers/input/touchscreen/touchright.c @@ -102,7 +102,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - tr = kzalloc(sizeof(*tr), GFP_KERNEL); + tr = kzalloc_obj(*tr); input_dev = input_allocate_device(); if (!tr || !input_dev) { err = -ENOMEM; @@ -111,7 +111,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv) tr->serio = serio; tr->dev = input_dev; - snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); + scnprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys); input_dev->name = "Touchright Serial TouchScreen"; input_dev->phys = tr->phys; diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c index fbd72789ea80..099fd88e65d8 100644 --- a/drivers/input/touchscreen/touchwin.c +++ b/drivers/input/touchscreen/touchwin.c @@ -109,7 +109,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int err; - tw = kzalloc(sizeof(*tw), GFP_KERNEL); + tw = kzalloc_obj(*tw); input_dev = input_allocate_device(); if (!tw || !input_dev) { err = -ENOMEM; @@ -118,7 +118,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv) tw->serio = serio; tw->dev = input_dev; - snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); + scnprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys); input_dev->name = "Touchwindow Serial TouchScreen"; input_dev->phys = tw->phys; diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h index 69b08dd6c8df..e346fb4f7552 100644 --- a/drivers/input/touchscreen/tsc2007.h +++ b/drivers/input/touchscreen/tsc2007.h @@ -19,6 +19,7 @@ #ifndef _TSC2007_H #define _TSC2007_H +#include <linux/input/touchscreen.h> struct gpio_desc; #define TSC2007_MEASURE_TEMP0 (0x0 << 4) @@ -63,6 +64,7 @@ struct tsc2007 { struct i2c_client *client; + struct touchscreen_properties prop; u16 model; u16 x_plate_ohms; u16 max_rt; diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 8d832a372b89..524f14eb3da2 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -23,6 +23,7 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/i2c.h> +#include <linux/math64.h> #include <linux/mod_devicetable.h> #include <linux/property.h> #include <linux/platform_data/tsc2007.h> @@ -68,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) { - u32 rt = 0; + u64 rt = 0; /* range filtering */ if (tc->x == MAX_12BIT) @@ -79,11 +80,13 @@ u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) rt = tc->z2 - tc->z1; rt *= tc->x; rt *= tsc->x_plate_ohms; - rt /= tc->z1; + rt = div_u64(rt, tc->z1); rt = (rt + 2047) >> 12; } - return rt; + if (rt > U32_MAX) + return U32_MAX; + return (u32) rt; } bool tsc2007_is_pen_down(struct tsc2007 *ts) @@ -119,9 +122,10 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) /* pen is down, continue with the measurement */ - mutex_lock(&ts->mlock); - tsc2007_read_values(ts, &tc); - mutex_unlock(&ts->mlock); + /* Serialize access between the ISR and IIO reads. */ + scoped_guard(mutex, &ts->mlock) { + tsc2007_read_values(ts, &tc); + } rt = tsc2007_calculate_resistance(ts, &tc); @@ -142,8 +146,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) rt = ts->max_rt - rt; input_report_key(input, BTN_TOUCH, 1); - input_report_abs(input, ABS_X, tc.x); - input_report_abs(input, ABS_Y, tc.y); + touchscreen_report_pos(input, &ts->prop, tc.x, tc.y, false); input_report_abs(input, ABS_PRESSURE, rt); input_sync(input); @@ -178,7 +181,8 @@ static void tsc2007_stop(struct tsc2007 *ts) mb(); wake_up(&ts->wait); - disable_irq(ts->irq); + if (ts->irq) + disable_irq(ts->irq); } static int tsc2007_open(struct input_dev *input_dev) @@ -189,7 +193,8 @@ static int tsc2007_open(struct input_dev *input_dev) ts->stopped = false; mb(); - enable_irq(ts->irq); + if (ts->irq) + enable_irq(ts->irq); /* Prepare for touch readings - power down ADC and enable PENIRQ */ err = tsc2007_xfer(ts, PWRDOWN); @@ -254,7 +259,7 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) if (ts->gpiod) ts->get_pendown_state = tsc2007_get_pendown_state_gpio; else - dev_warn(dev, "Pen down GPIO is not specified in properties\n"); + dev_dbg(dev, "Pen down GPIO is not specified in properties\n"); return 0; } @@ -339,9 +344,9 @@ static int tsc2007_probe(struct i2c_client *client) input_set_drvdata(input_dev, ts); input_set_capability(input_dev, EV_KEY, BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); + touchscreen_parse_properties(input_dev, false, &ts->prop); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, ts->fuzzz, 0); @@ -362,17 +367,19 @@ static int tsc2007_probe(struct i2c_client *client) pdata->init_platform_hw(); } - err = devm_request_threaded_irq(&client->dev, ts->irq, - NULL, tsc2007_soft_irq, - IRQF_ONESHOT, - client->dev.driver->name, ts); - if (err) { - dev_err(&client->dev, "Failed to request irq %d: %d\n", - ts->irq, err); - return err; - } + if (ts->irq) { + err = devm_request_threaded_irq(&client->dev, ts->irq, + NULL, tsc2007_soft_irq, + IRQF_ONESHOT, + client->dev.driver->name, ts); + if (err) { + dev_err(&client->dev, "Failed to request irq %d: %d\n", + ts->irq, err); + return err; + } - tsc2007_stop(ts); + tsc2007_stop(ts); + } /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ err = tsc2007_xfer(ts, PWRDOWN); diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c index 752eb7fe5da3..e9e495ec0b6c 100644 --- a/drivers/input/touchscreen/tsc2007_iio.c +++ b/drivers/input/touchscreen/tsc2007_iio.c @@ -41,7 +41,6 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev, struct tsc2007_iio *iio = iio_priv(indio_dev); struct tsc2007 *tsc = iio->ts; int adc_chan = chan->channel; - int ret = 0; if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel)) return -EINVAL; @@ -49,7 +48,7 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev, if (mask != IIO_CHAN_INFO_RAW) return -EINVAL; - mutex_lock(&tsc->mlock); + guard(mutex)(&tsc->mlock); switch (chan->channel) { case 0: @@ -92,11 +91,7 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev, /* Prepare for next touch reading - power down ADC, enable PENIRQ */ tsc2007_xfer(tsc, PWRDOWN); - mutex_unlock(&tsc->mlock); - - ret = IIO_VAL_INT; - - return ret; + return IIO_VAL_INT; } static const struct iio_info tsc2007_iio_info = { diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index df39dee13e1c..eba53613b005 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -10,6 +10,7 @@ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com> */ +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/input.h> @@ -194,7 +195,7 @@ out: static void tsc200x_penup_timer(struct timer_list *t) { - struct tsc200x *ts = from_timer(ts, t, penup_timer); + struct tsc200x *ts = timer_container_of(ts, t, penup_timer); guard(spinlock_irqsave)(&ts->lock); tsc200x_update_pen_state(ts, 0, 0, 0); @@ -229,7 +230,7 @@ static void __tsc200x_disable(struct tsc200x *ts) guard(disable_irq)(&ts->irq); - del_timer_sync(&ts->penup_timer); + timer_delete_sync(&ts->penup_timer); cancel_delayed_work_sync(&ts->esd_work); } @@ -388,7 +389,7 @@ static void tsc200x_esd_work(struct work_struct *work) dev_info(ts->dev, "TSC200X not responding - resetting\n"); scoped_guard(disable_irq, &ts->irq) { - del_timer_sync(&ts->penup_timer); + timer_delete_sync(&ts->penup_timer); tsc200x_update_pen_state(ts, 0, 0, 0); tsc200x_reset(ts); } diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c index 9f485cf57a72..2a28a309eab5 100644 --- a/drivers/input/touchscreen/tsc40.c +++ b/drivers/input/touchscreen/tsc40.c @@ -83,7 +83,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv) struct input_dev *input_dev; int error; - ptsc = kzalloc(sizeof(*ptsc), GFP_KERNEL); + ptsc = kzalloc_obj(*ptsc); input_dev = input_allocate_device(); if (!ptsc || !input_dev) { error = -ENOMEM; @@ -92,7 +92,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv) ptsc->serio = serio; ptsc->dev = input_dev; - snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys); + scnprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys); input_dev->name = "TSC-10/25/40 Serial TouchScreen"; input_dev->phys = ptsc->phys; diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 7567efabe014..0bbacb517c28 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c @@ -378,7 +378,7 @@ static int mtouch_alloc(struct usbtouch_usb *usbtouch) { struct mtouch_priv *priv; - priv = kmalloc(sizeof(*priv), GFP_KERNEL); + priv = kmalloc_obj(*priv); if (!priv) return -ENOMEM; @@ -938,7 +938,7 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch) struct nexio_priv *priv; int ret = -ENOMEM; - priv = kmalloc(sizeof(*priv), GFP_KERNEL); + priv = kmalloc_obj(*priv); if (!priv) goto out_buf; @@ -969,24 +969,21 @@ static int nexio_init(struct usbtouch_usb *usbtouch) { struct usb_device *dev = interface_to_usbdev(usbtouch->interface); struct usb_host_interface *interface = usbtouch->interface->cur_altsetting; + struct usb_endpoint_descriptor *ep_in, *ep_out; struct nexio_priv *priv = usbtouch->priv; - int ret = -ENOMEM; int actual_len, i; char *firmware_ver = NULL, *device_name = NULL; - int input_ep = 0, output_ep = 0; + int input_ep, output_ep; + int ret; /* find first input and output endpoint */ - for (i = 0; i < interface->desc.bNumEndpoints; i++) { - if (!input_ep && - usb_endpoint_dir_in(&interface->endpoint[i].desc)) - input_ep = interface->endpoint[i].desc.bEndpointAddress; - if (!output_ep && - usb_endpoint_dir_out(&interface->endpoint[i].desc)) - output_ep = interface->endpoint[i].desc.bEndpointAddress; - } - if (!input_ep || !output_ep) + ret = usb_find_common_endpoints(interface, &ep_in, &ep_out, NULL, NULL); + if (ret) return -ENXIO; + input_ep = usb_endpoint_num(ep_in); + output_ep = usb_endpoint_num(ep_out); + u8 *buf __free(kfree) = kmalloc(NEXIO_BUFSIZE, GFP_NOIO); if (!buf) return -ENOMEM; @@ -1070,6 +1067,11 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) if (x_len > 0xff) x_len -= 0x80; + if (data_len > usbtouch->data_size - sizeof(*packet)) + data_len = usbtouch->data_size - sizeof(*packet); + if (x_len > data_len) + x_len = data_len; + /* send ACK */ ret = usb_submit_urb(priv->ack, GFP_ATOMIC); if (ret) @@ -1427,18 +1429,6 @@ static void usbtouch_free_buffers(struct usb_device *udev, kfree(usbtouch->buffer); } -static struct usb_endpoint_descriptor * -usbtouch_get_input_endpoint(struct usb_host_interface *interface) -{ - int i; - - for (i = 0; i < interface->desc.bNumEndpoints; i++) - if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) - return &interface->endpoint[i].desc; - - return NULL; -} - static int usbtouch_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1447,18 +1437,22 @@ static int usbtouch_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *endpoint; struct usb_device *udev = interface_to_usbdev(intf); const struct usbtouch_device_info *type; - int err = -ENOMEM; + int err; /* some devices are ignored */ type = (const struct usbtouch_device_info *)id->driver_info; if (!type) return -ENODEV; - endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting); - if (!endpoint) - return -ENXIO; + err = usb_find_int_in_endpoint(intf->cur_altsetting, &endpoint); + if (err) { + err = usb_find_bulk_in_endpoint(intf->cur_altsetting, &endpoint); + if (err) + return -ENXIO; + } - usbtouch = kzalloc(sizeof(*usbtouch), GFP_KERNEL); + err = -ENOMEM; + usbtouch = kzalloc_obj(*usbtouch); input_dev = input_allocate_device(); if (!usbtouch || !input_dev) goto out_free; diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index ed2ca8a689d5..45930d731873 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c @@ -596,7 +596,7 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) char basename[64] = "Wacom Serial"; int err, err_pen, err_touch; - w8001 = kzalloc(sizeof(*w8001), GFP_KERNEL); + w8001 = kzalloc_obj(*w8001); input_dev_pen = input_allocate_device(); input_dev_touch = input_allocate_device(); if (!w8001 || !input_dev_pen || !input_dev_touch) { diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 88d376090e6e..bdaabb14dc8c 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -813,56 +813,46 @@ static int wdt87xx_load_chunk(struct i2c_client *client, return 0; } -static int wdt87xx_do_update_firmware(struct i2c_client *client, +static int wdt87xx_do_update_firmware(struct wdt87xx_data *wdt, const struct firmware *fw, unsigned int chunk_id) { - struct wdt87xx_data *wdt = i2c_get_clientdata(client); + struct i2c_client *client = wdt->client; int error; - error = wdt87xx_validate_firmware(wdt, fw); - if (error) - return error; - - error = mutex_lock_interruptible(&wdt->fw_mutex); - if (error) - return error; - - disable_irq(client->irq); - error = wdt87xx_load_chunk(client, fw, chunk_id); if (error) { dev_err(&client->dev, "firmware load failed (type: %d): %d\n", chunk_id, error); - goto out; + return error; } error = wdt87xx_sw_reset(client); if (error) { dev_err(&client->dev, "soft reset failed: %d\n", error); - goto out; + return error; } /* Refresh the parameters */ error = wdt87xx_get_sysparam(client, &wdt->param); - if (error) + if (error) { dev_err(&client->dev, "failed to refresh system parameters: %d\n", error); -out: - enable_irq(client->irq); - mutex_unlock(&wdt->fw_mutex); + return error; + } - return error ? error : 0; + return 0; } static int wdt87xx_update_firmware(struct device *dev, const char *fw_name, unsigned int chunk_id) { struct i2c_client *client = to_i2c_client(dev); - const struct firmware *fw; + struct wdt87xx_data *wdt = i2c_get_clientdata(client); int error; + const struct firmware *fw __free(firmware) = NULL; error = request_firmware(&fw, fw_name, dev); if (error) { dev_err(&client->dev, "unable to retrieve firmware %s: %d\n", @@ -870,11 +860,19 @@ static int wdt87xx_update_firmware(struct device *dev, return error; } - error = wdt87xx_do_update_firmware(client, fw, chunk_id); + error = wdt87xx_validate_firmware(wdt, fw); + if (error) + return error; - release_firmware(fw); + scoped_cond_guard(mutex_intr, return -EINTR, &wdt->fw_mutex) { + guard(disable_irq)(&client->irq); + + error = wdt87xx_do_update_firmware(wdt, fw, chunk_id); + if (error) + return error; + } - return error ? error : 0; + return 0; } static ssize_t config_csum_show(struct device *dev, @@ -1026,10 +1024,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) int error; input = devm_input_allocate_device(dev); - if (!input) { - dev_err(dev, "failed to allocate input device\n"); + if (!input) return -ENOMEM; - } wdt->input = input; input->name = "WDT87xx Touchscreen"; @@ -1053,10 +1049,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); error = input_register_device(input); - if (error) { - dev_err(dev, "failed to register input device: %d\n", error); - return error; - } + if (error) + return dev_err_probe(dev, error, "failed to register input device\n"); return 0; } @@ -1096,10 +1090,8 @@ static int wdt87xx_ts_probe(struct i2c_client *client) NULL, wdt87xx_ts_interrupt, IRQF_ONESHOT, client->name, wdt); - if (error) { - dev_err(&client->dev, "request irq failed: %d\n", error); + if (error) return error; - } return 0; } diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c index 4b55d5e1ea0f..96484aae030c 100644 --- a/drivers/input/touchscreen/wm9705.c +++ b/drivers/input/touchscreen/wm9705.c @@ -9,6 +9,7 @@ * Russell King <rmk@arm.linux.org.uk> */ +#include <linux/export.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c index 6947714dfefa..087ece57741a 100644 --- a/drivers/input/touchscreen/wm9712.c +++ b/drivers/input/touchscreen/wm9712.c @@ -9,6 +9,7 @@ * Russell King <rmk@arm.linux.org.uk> */ +#include <linux/export.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c index a67fbe304f92..6f13f46ce6e6 100644 --- a/drivers/input/touchscreen/wm9713.c +++ b/drivers/input/touchscreen/wm9713.c @@ -9,6 +9,7 @@ * Russell King <rmk@arm.linux.org.uk> */ +#include <linux/export.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index b25771a8df2b..c51822563f3f 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -29,6 +29,7 @@ * - Support for async sampling control for noisy LCDs. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> @@ -125,7 +126,7 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) int timeout = 0; /* get codec */ - mutex_lock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); /* When the touchscreen is not in use, we may have to power up * the AUX ADC before we can use sample the AUX inputs-> @@ -159,7 +160,6 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel) wm->codec->dig_enable(wm, false); } - mutex_unlock(&wm->codec_mutex); return (rc == RC_VALID ? auxval & 0xfff : -EBUSY); } EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); @@ -175,18 +175,11 @@ EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc); enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio) { u16 status; - enum wm97xx_gpio_status ret; - mutex_lock(&wm->codec_mutex); - status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); - - if (status & gpio) - ret = WM97XX_GPIO_HIGH; - else - ret = WM97XX_GPIO_LOW; + guard(mutex)(&wm->codec_mutex); - mutex_unlock(&wm->codec_mutex); - return ret; + status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); + return (status & gpio) ? WM97XX_GPIO_HIGH : WM97XX_GPIO_LOW; } EXPORT_SYMBOL_GPL(wm97xx_get_gpio); @@ -204,7 +197,8 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, { u16 reg; - mutex_lock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); + reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS); if (status == WM97XX_GPIO_HIGH) @@ -216,7 +210,6 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio, wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1); else wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg); - mutex_unlock(&wm->codec_mutex); } EXPORT_SYMBOL_GPL(wm97xx_set_gpio); @@ -230,7 +223,8 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir, { u16 reg; - mutex_lock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); + reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); if (pol == WM97XX_GPIO_POL_HIGH) @@ -263,7 +257,6 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir, reg &= ~gpio; wm97xx_reg_write(wm, AC97_GPIO_CFG, reg); - mutex_unlock(&wm->codec_mutex); } EXPORT_SYMBOL_GPL(wm97xx_config_gpio); @@ -302,7 +295,9 @@ static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) wm->pen_is_down = 0; } else { u16 status, pol; - mutex_lock(&wm->codec_mutex); + + guard(mutex)(&wm->codec_mutex); + status = wm97xx_reg_read(wm, AC97_GPIO_STATUS); pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY); @@ -322,7 +317,6 @@ static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id) else wm97xx_reg_write(wm, AC97_GPIO_STATUS, status & ~WM97XX_GPIO_13); - mutex_unlock(&wm->codec_mutex); } /* If the system is not using continuous mode or it provides a @@ -381,7 +375,7 @@ static int wm97xx_read_samples(struct wm97xx *wm) struct wm97xx_data data; int rc; - mutex_lock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); if (wm->mach_ops && wm->mach_ops->acc_enabled) rc = wm->mach_ops->acc_pen_down(wm); @@ -421,8 +415,7 @@ static int wm97xx_read_samples(struct wm97xx *wm) abs_y[0] > (data.y & 0xfff) || abs_y[1] < (data.y & 0xfff)) { dev_dbg(wm->dev, "Measurement out of range, dropping it\n"); - rc = RC_AGAIN; - goto out; + return RC_AGAIN; } input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff); @@ -438,8 +431,6 @@ static int wm97xx_read_samples(struct wm97xx *wm) wm->ts_reader_interval = wm->ts_reader_min_interval; } -out: - mutex_unlock(&wm->codec_mutex); return rc; } @@ -772,7 +763,8 @@ static int wm97xx_suspend(struct device *dev) else suspend_mode = 0; - mutex_lock(&wm->input_dev->mutex); + guard(mutex)(&wm->input_dev->mutex); + if (input_device_enabled(wm->input_dev)) cancel_delayed_work_sync(&wm->ts_reader); @@ -790,7 +782,6 @@ static int wm97xx_suspend(struct device *dev) reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000; wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg); } - mutex_unlock(&wm->input_dev->mutex); return 0; } @@ -799,7 +790,8 @@ static int wm97xx_resume(struct device *dev) { struct wm97xx *wm = dev_get_drvdata(dev); - mutex_lock(&wm->input_dev->mutex); + guard(mutex)(&wm->input_dev->mutex); + /* restore digitiser and gpios */ if (wm->id == WM9713_ID2) { wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]); @@ -826,7 +818,6 @@ static int wm97xx_resume(struct device *dev) queue_delayed_work(wm->ts_workq, &wm->ts_reader, wm->ts_reader_interval); } - mutex_unlock(&wm->input_dev->mutex); return 0; } @@ -839,13 +830,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume); int wm97xx_register_mach_ops(struct wm97xx *wm, struct wm97xx_mach_ops *mach_ops) { - mutex_lock(&wm->codec_mutex); - if (wm->mach_ops) { - mutex_unlock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); + + if (wm->mach_ops) return -EINVAL; - } + wm->mach_ops = mach_ops; - mutex_unlock(&wm->codec_mutex); return 0; } @@ -853,9 +843,9 @@ EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops); void wm97xx_unregister_mach_ops(struct wm97xx *wm) { - mutex_lock(&wm->codec_mutex); + guard(mutex)(&wm->codec_mutex); + wm->mach_ops = NULL; - mutex_unlock(&wm->codec_mutex); } EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index df42fdf36ae3..a360749fa076 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -747,8 +747,7 @@ static int zforce_probe(struct i2c_client *client) input_dev = devm_input_allocate_device(&client->dev); if (!input_dev) - return dev_err_probe(&client->dev, -ENOMEM, - "could not allocate input device\n"); + return -ENOMEM; ts->client = client; ts->input = input_dev; diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 716d6fa60f86..0c36765bd79f 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -703,13 +703,11 @@ static int 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); + guard(mutex)(&bt541->input_dev->mutex); if (input_device_enabled(bt541->input_dev)) zinitix_stop(bt541); - mutex_unlock(&bt541->input_dev->mutex); - return 0; } @@ -717,16 +715,17 @@ static int 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); + int error; - if (input_device_enabled(bt541->input_dev)) - ret = zinitix_start(bt541); + guard(mutex)(&bt541->input_dev->mutex); - mutex_unlock(&bt541->input_dev->mutex); + if (input_device_enabled(bt541->input_dev)) { + error = zinitix_start(bt541); + if (error) + return error; + } - return ret; + return 0; } static DEFINE_SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume); |
