diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:38:20 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-03 12:38:20 -0700 |
commit | 16a12fa9aed176444fc795b09e796be41902bb08 (patch) | |
tree | bd158def3263a8b0d0f0886fd0fcd32728242dc4 /drivers | |
parent | d25e436c4b68db2895185b24ad1f22499c2f87b0 (diff) | |
parent | 0337966d121ebebf73a1c346123e8112796e684e (diff) | |
download | linux-16a12fa9aed176444fc795b09e796be41902bb08.tar.bz2 |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input subsystem updates from Dmitry Torokhov:
- a big update from Mauro converting input documentation to ReST format
- Synaptics PS/2 is now aware of SMBus companion devices, which means
that we can now use native RMI4 protocol to handle touchpads, instead
of relying on legacy PS/2 mode.
- we removed support from BMA180 accelerometer from input devices as it
is now handled properly by IIO
- update to TSC2007 to corretcly report pressure
- other miscellaneous driver fixes.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (152 commits)
Input: ar1021_i2c - use BIT to check for a bit
Input: twl4030-pwrbutton - use input_set_capability() helper
Input: twl4030-pwrbutton - use correct device for irq request
Input: ar1021_i2c - enable touch mode during open
Input: add uinput documentation
dt-bindings: input: add bindings document for ar1021_i2c driver
dt-bindings: input: rotary-encoder: fix typo
Input: xen-kbdfront - add module parameter for setting resolution
ARM: pxa/raumfeld: fix compile error in rotary controller resources
Input: xpad - do not suggest writing to Dominic
Input: xpad - don't use literal blocks inside footnotes
Input: xpad - note that usb/devices is now at /sys/kernel/debug/
Input: docs - freshen up introduction
Input: docs - split input docs into kernel- and user-facing
Input: docs - note that MT-A protocol is obsolete
Input: docs - update joystick documentation a bit
Input: docs - remove disclaimer/GPL notice
Input: fix "Game console" heading level in joystick documentation
Input: rotary-encoder - remove references to platform data from docs
Input: move documentation for Amiga CD32
...
Diffstat (limited to 'drivers')
65 files changed, 2613 insertions, 1492 deletions
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index 6e5fac6a5262..31186ead5a40 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -15,6 +15,7 @@ #include <linux/export.h> #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/property.h> #include <linux/rwsem.h> #include <linux/slab.h> @@ -55,6 +56,7 @@ EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); * * The board info passed can safely be __initdata, but be careful of embedded * pointers (for platform_data, functions, etc) since that won't be copied. + * Device properties are deep-copied though. */ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) { @@ -78,6 +80,28 @@ int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsig devinfo->busnum = busnum; devinfo->board_info = *info; + + if (info->properties) { + devinfo->board_info.properties = + property_entries_dup(info->properties); + if (IS_ERR(devinfo->board_info.properties)) { + status = PTR_ERR(devinfo->board_info.properties); + break; + } + } + + if (info->resources) { + devinfo->board_info.resources = + kmemdup(info->resources, + info->num_resources * + sizeof(*info->resources), + GFP_KERNEL); + if (!devinfo->board_info.resources) { + status = -ENOMEM; + break; + } + } + list_add_tail(&devinfo->list, &__i2c_board_list); } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7a065c4260f3..82576aaccc90 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -74,7 +74,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -static struct device_type i2c_client_type; static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; @@ -1153,11 +1152,12 @@ struct bus_type i2c_bus_type = { }; EXPORT_SYMBOL_GPL(i2c_bus_type); -static struct device_type i2c_client_type = { +struct device_type i2c_client_type = { .groups = i2c_dev_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, }; +EXPORT_SYMBOL_GPL(i2c_client_type); /** @@ -1334,6 +1334,32 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, i2c_encode_flags_to_addr(client)); } +static int i2c_dev_irq_from_resources(const struct resource *resources, + unsigned int num_resources) +{ + struct irq_data *irqd; + int i; + + for (i = 0; i < num_resources; i++) { + const struct resource *r = &resources[i]; + + if (resource_type(r) != IORESOURCE_IRQ) + continue; + + if (r->flags & IORESOURCE_BITS) { + irqd = irq_get_irq_data(r->start); + if (!irqd) + break; + + irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); + } + + return r->start; + } + + return 0; +} + /** * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device @@ -1369,7 +1395,11 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->flags = info->flags; client->addr = info->addr; + client->irq = info->irq; + if (!client->irq) + client->irq = i2c_dev_irq_from_resources(info->resources, + info->num_resources); strlcpy(client->name, info->type, sizeof(client->name)); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 4a2a9e370be7..cedc665364cd 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -385,8 +385,8 @@ static int gameport_queue_event(void *object, struct module *owner, } if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); + pr_warn("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; @@ -542,9 +542,8 @@ static void gameport_init_port(struct gameport *gameport) INIT_LIST_HEAD(&gameport->node); spin_lock_init(&gameport->timer_lock); - init_timer(&gameport->poll_timer); - gameport->poll_timer.function = gameport_run_poll_handler; - gameport->poll_timer.data = (unsigned long)gameport; + setup_timer(&gameport->poll_timer, gameport_run_poll_handler, + (unsigned long)gameport); } /* diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c index da326090c2b0..f4ad83eab67f 100644 --- a/drivers/input/joystick/db9.c +++ b/drivers/input/joystick/db9.c @@ -609,9 +609,7 @@ static void db9_attach(struct parport *pp) db9->pd = pd; db9->mode = mode; db9->parportno = pp->number; - init_timer(&db9->timer); - db9->timer.data = (long) db9; - db9->timer.function = db9_timer; + setup_timer(&db9->timer, db9_timer, (long)db9); for (i = 0; i < (min(db9_mode->n_pads, DB9_MAX_DEVICES)); i++) { diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index eae14d512353..c43f087a496d 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -870,7 +870,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type) err = gc_n64_init_ff(input_dev, idx); if (err) { - pr_warning("Failed to initiate rumble for N64 device %d\n", idx); + pr_warn("Failed to initiate rumble for N64 device %d\n", + idx); goto err_free_dev; } diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c index 77f575dd0901..a1fdc75a438d 100644 --- a/drivers/input/joystick/turbografx.c +++ b/drivers/input/joystick/turbografx.c @@ -200,9 +200,7 @@ static void tgfx_attach(struct parport *pp) mutex_init(&tgfx->sem); tgfx->pd = pd; tgfx->parportno = pp->number; - init_timer(&tgfx->timer); - tgfx->timer.data = (long) tgfx; - tgfx->timer.function = tgfx_timer; + setup_timer(&tgfx->timer, tgfx_timer, (long)tgfx); for (i = 0; i < n_devs; i++) { if (n_buttons[i] < 1) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 153b1ee13e03..df83fdc6c0e7 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -339,6 +339,64 @@ static struct usb_device_id xpad_table[] = { MODULE_DEVICE_TABLE(usb, xpad_table); +struct xboxone_init_packet { + u16 idVendor; + u16 idProduct; + const u8 *data; + u8 len; +}; + +#define XBOXONE_INIT_PKT(_vid, _pid, _data) \ + { \ + .idVendor = (_vid), \ + .idProduct = (_pid), \ + .data = (_data), \ + .len = ARRAY_SIZE(_data), \ + } + + +/* + * This packet is required for all Xbox One pads with 2015 + * or later firmware installed (or present from the factory). + */ +static const u8 xboxone_fw2015_init[] = { + 0x05, 0x20, 0x00, 0x01, 0x00 +}; + +/* + * This packet is required for the Titanfall 2 Xbox One pads + * (0x0e6f:0x0165) to finish initialization and for Hori pads + * (0x0f0d:0x0067) to make the analog sticks work. + */ +static const u8 xboxone_hori_init[] = { + 0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a, + 0x00, 0x00, 0x00, 0x80, 0x00 +}; + +/* + * A rumble packet is required for some PowerA pads to start + * sending input reports. One of those pads is (0x24c6:0x543a). + */ +static const u8 xboxone_zerorumble_init[] = { + 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* + * This specifies the selection of init packets that a gamepad + * will be sent on init *and* the order in which they will be + * sent. The correct sequence number will be added when the + * packet is going to be sent. + */ +static const struct xboxone_init_packet xboxone_init_packets[] = { + XBOXONE_INIT_PKT(0x0e6f, 0x0165, xboxone_hori_init), + XBOXONE_INIT_PKT(0x0f0d, 0x0067, xboxone_hori_init), + XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_fw2015_init), + XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_zerorumble_init), + XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_zerorumble_init), + XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_zerorumble_init), +}; + struct xpad_output_packet { u8 data[XPAD_PKT_LEN]; u8 len; @@ -375,6 +433,7 @@ struct usb_xpad { struct xpad_output_packet out_packets[XPAD_NUM_OUT_PACKETS]; int last_out_packet; + int init_seq; #if defined(CONFIG_JOYSTICK_XPAD_LEDS) struct xpad_led *led; @@ -750,11 +809,47 @@ exit: } /* Callers must hold xpad->odata_lock spinlock */ +static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad) +{ + const struct xboxone_init_packet *init_packet; + + if (xpad->xtype != XTYPE_XBOXONE) + return false; + + /* Perform initialization sequence for Xbox One pads that require it */ + while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) { + init_packet = &xboxone_init_packets[xpad->init_seq++]; + + if (init_packet->idVendor != 0 && + init_packet->idVendor != xpad->dev->id.vendor) + continue; + + if (init_packet->idProduct != 0 && + init_packet->idProduct != xpad->dev->id.product) + continue; + + /* This packet applies to our device, so prepare to send it */ + memcpy(xpad->odata, init_packet->data, init_packet->len); + xpad->irq_out->transfer_buffer_length = init_packet->len; + + /* Update packet with current sequence number */ + xpad->odata[2] = xpad->odata_serial++; + return true; + } + + return false; +} + +/* Callers must hold xpad->odata_lock spinlock */ static bool xpad_prepare_next_out_packet(struct usb_xpad *xpad) { struct xpad_output_packet *pkt, *packet = NULL; int i; + /* We may have init packets to send before we can send user commands */ + if (xpad_prepare_next_init_packet(xpad)) + return true; + for (i = 0; i < XPAD_NUM_OUT_PACKETS; i++) { if (++xpad->last_out_packet >= XPAD_NUM_OUT_PACKETS) xpad->last_out_packet = 0; @@ -940,24 +1035,17 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad) static int xpad_start_xbox_one(struct usb_xpad *xpad) { - struct xpad_output_packet *packet = - &xpad->out_packets[XPAD_OUT_CMD_IDX]; unsigned long flags; int retval; spin_lock_irqsave(&xpad->odata_lock, flags); - /* Xbox one controller needs to be initialized. */ - packet->data[0] = 0x05; - packet->data[1] = 0x20; - packet->data[2] = xpad->odata_serial++; /* packet serial */ - packet->data[3] = 0x01; /* rumble bit enable? */ - packet->data[4] = 0x00; - packet->len = 5; - packet->pending = true; - - /* Reset the sequence so we send out start packet first */ - xpad->last_out_packet = -1; + /* + * Begin the init sequence by attempting to send a packet. + * We will cycle through the init packet sequence before + * sending any packets from the output ring. + */ + xpad->init_seq = 0; retval = xpad_try_sending_next_out_packet(xpad); spin_unlock_irqrestore(&xpad->odata_lock, flags); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 6a250d65f8fe..c7a8120b13c0 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -30,6 +30,7 @@ #include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/sysrq.h> #include <linux/input/matrix_keypad.h> #include <linux/mfd/cros_ec.h> #include <linux/mfd/cros_ec_commands.h> @@ -260,6 +261,12 @@ static int cros_ec_keyb_work(struct notifier_block *nb, ckdev->ec->event_size); break; + case EC_MKBP_EVENT_SYSRQ: + val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq); + dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val); + handle_sysrq(val); + break; + case EC_MKBP_EVENT_BUTTON: case EC_MKBP_EVENT_SWITCH: /* diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c index c94d610b9d78..0d74312d5b02 100644 --- a/drivers/input/keyboard/locomokbd.c +++ b/drivers/input/keyboard/locomokbd.c @@ -264,9 +264,8 @@ static int locomokbd_probe(struct locomo_dev *dev) spin_lock_init(&locomokbd->lock); - init_timer(&locomokbd->timer); - locomokbd->timer.function = locomokbd_timer_callback; - locomokbd->timer.data = (unsigned long) locomokbd; + setup_timer(&locomokbd->timer, locomokbd_timer_callback, + (unsigned long)locomokbd); locomokbd->suspend_jiffies = jiffies; diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 18839cd5f76e..1f316d66e6f7 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -42,9 +42,10 @@ struct matrix_keypad { }; /* - * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause - * minmal side effect when scanning other columns, here it is configured to - * be input, and it should work on most platforms. + * NOTE: If drive_inactive_cols is false, then the GPIO has to be put into + * HiZ when de-activated to cause minmal side effect when scanning other + * columns. In that case it is configured here to be input, otherwise it is + * driven with the inactive value. */ static void __activate_col(const struct matrix_keypad_platform_data *pdata, int col, bool on) @@ -55,7 +56,8 @@ static void __activate_col(const struct matrix_keypad_platform_data *pdata, gpio_direction_output(pdata->col_gpios[col], level_on); } else { gpio_set_value_cansleep(pdata->col_gpios[col], !level_on); - gpio_direction_input(pdata->col_gpios[col]); + if (!pdata->drive_inactive_cols) + gpio_direction_input(pdata->col_gpios[col]); } } @@ -432,6 +434,9 @@ matrix_keypad_parse_dt(struct device *dev) if (of_get_property(np, "gpio-activelow", NULL)) pdata->active_low = true; + pdata->drive_inactive_cols = + of_property_read_bool(np, "drive-inactive-cols"); + of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms); of_property_read_u32(np, "col-scan-delay-us", &pdata->col_scan_delay_us); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index ebc67ba41fe2..940d38b08e6b 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -358,7 +358,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) "omap4-keypad", keypad_data); if (error) { dev_err(&pdev->dev, "failed to register interrupt\n"); - goto err_free_input; + goto err_free_keymap; } device_init_wakeup(&pdev->dev, true); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 5a5778729e37..76bb51309a78 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -274,9 +274,18 @@ static const struct i2c_device_id qt1070_id[] = { }; MODULE_DEVICE_TABLE(i2c, qt1070_id); +#ifdef CONFIG_OF +static const struct of_device_id qt1070_of_match[] = { + { .compatible = "qt1070", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qt1070_of_match); +#endif + static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", + .of_match_table = of_match_ptr(qt1070_of_match), .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 44dd7689c571..e37e335e406f 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -188,8 +188,6 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) input_event(input, EV_MSC, MSC_SCAN, code); input_report_key(input, keymap[code], state); - /* Read for next loop */ - error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); } while (1); input_sync(input); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 9f7b72249eac..3872488c3fd7 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -143,7 +143,7 @@ config INPUT_PM8941_PWRKEY config INPUT_PM8XXX_VIBRATOR tristate "Qualcomm PM8XXX vibrator support" - depends on MFD_PM8XXX + depends on MFD_PM8XXX || MFD_SPMI_PMIC select INPUT_FF_MEMLESS help This option enables device driver support for the vibrator diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index 53630afab606..aad1df04c854 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -314,7 +314,8 @@ static int __init apanel_init(void) if (devno >= APANEL_DEV_MAX) pr_notice(APANEL ": unknown device %u found\n", devno); else if (device_chip[devno] != CHIP_NONE) - pr_warning(APANEL ": duplicate entry for devno %u\n", devno); + pr_warn(APANEL ": duplicate entry for devno %u\n", + devno); else if (method != 1 && method != 2 && method != 4) { pr_notice(APANEL ": unknown method %u for devno %u\n", diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 1ac898db303a..f11807db6979 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include <linux/acpi.h> #include <linux/errno.h> #include <linux/irq.h> #include <linux/init.h> @@ -188,21 +189,13 @@ static void axp20x_remove_sysfs_group(void *_data) sysfs_remove_group(&dev->kobj, &axp20x_attribute_group); } -static int axp20x_pek_probe(struct platform_device *pdev) +static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, + struct platform_device *pdev) { - struct axp20x_pek *axp20x_pek; - struct axp20x_dev *axp20x; + struct axp20x_dev *axp20x = axp20x_pek->axp20x; struct input_dev *idev; int error; - axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), - GFP_KERNEL); - if (!axp20x_pek) - return -ENOMEM; - - axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); - axp20x = axp20x_pek->axp20x; - axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); if (axp20x_pek->irq_dbr < 0) { dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n", @@ -239,7 +232,7 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek_irq, 0, "axp20x-pek-dbr", idev); if (error < 0) { - dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n", + dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", axp20x_pek->irq_dbr, error); return error; } @@ -248,30 +241,57 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek_irq, 0, "axp20x-pek-dbf", idev); if (error < 0) { - dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n", + dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", axp20x_pek->irq_dbf, error); return error; } - error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); + error = input_register_device(idev); if (error) { - dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n", + dev_err(&pdev->dev, "Can't register input device: %d\n", error); return error; } - error = devm_add_action(&pdev->dev, - axp20x_remove_sysfs_group, &pdev->dev); + return 0; +} + +static int axp20x_pek_probe(struct platform_device *pdev) +{ + struct axp20x_pek *axp20x_pek; + int error; + + axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek), + GFP_KERNEL); + if (!axp20x_pek) + return -ENOMEM; + + axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); + + /* + * Do not register the input device if there is an "INTCFD9" + * gpio button ACPI device, that handles the power button too, + * and otherwise we end up reporting all presses twice. + */ + if (!acpi_dev_found("INTCFD9") || + !IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY)) { + error = axp20x_pek_probe_input_device(axp20x_pek, pdev); + if (error) + return error; + } + + error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group); if (error) { - axp20x_remove_sysfs_group(&pdev->dev); - dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n", + dev_err(&pdev->dev, "Failed to create sysfs attributes: %d\n", error); return error; } - error = input_register_device(idev); + error = devm_add_action(&pdev->dev, + axp20x_remove_sysfs_group, &pdev->dev); if (error) { - dev_err(axp20x->dev, "Can't register input device: %d\n", + axp20x_remove_sysfs_group(&pdev->dev); + dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n", error); return error; } diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 1fa85379f86c..1efcfdf9f8a8 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -70,7 +70,6 @@ #define BMA150_CFG_5_REG 0x11 #define BMA150_CHIP_ID 2 -#define BMA180_CHIP_ID 3 #define BMA150_CHIP_ID_REG BMA150_DATA_0_REG #define BMA150_ACC_X_LSB_REG BMA150_DATA_2_REG @@ -538,13 +537,8 @@ static int bma150_probe(struct i2c_client *client, return -EIO; } - /* - * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail - * the probe for the bma180 as the iio driver is preferred. - */ chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); - if (chip_id != BMA150_CHIP_ID && - (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) { + if (chip_id != BMA150_CHIP_ID) { dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id); return -EINVAL; } @@ -648,9 +642,6 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); static const struct i2c_device_id bma150_id[] = { { "bma150", 0 }, -#if !IS_ENABLED(CONFIG_BMA180) - { "bma180", 0 }, -#endif { "smb380", 0 }, { "bma023", 0 }, { } diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c index 82e272ebc0ed..bab256ef32b9 100644 --- a/drivers/input/misc/dm355evm_keys.c +++ b/drivers/input/misc/dm355evm_keys.c @@ -32,7 +32,6 @@ struct dm355evm_keys { struct input_dev *input; struct device *dev; - int irq; }; /* These initial keycodes can be remapped */ @@ -176,74 +175,49 @@ static int dm355evm_keys_probe(struct platform_device *pdev) { struct dm355evm_keys *keys; struct input_dev *input; - int status; + int irq; + int error; - /* allocate instance struct and input dev */ - keys = kzalloc(sizeof *keys, GFP_KERNEL); - input = input_allocate_device(); - if (!keys || !input) { - status = -ENOMEM; - goto fail1; - } + keys = devm_kzalloc(&pdev->dev, sizeof (*keys), GFP_KERNEL); + if (!keys) + return -ENOMEM; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; keys->dev = &pdev->dev; keys->input = input; - /* set up "threaded IRQ handler" */ - status = platform_get_irq(pdev, 0); - if (status < 0) - goto fail1; - keys->irq = status; - input->name = "DM355 EVM Controls"; input->phys = "dm355evm/input0"; - input->dev.parent = &pdev->dev; input->id.bustype = BUS_I2C; input->id.product = 0x0355; input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); - status = sparse_keymap_setup(input, dm355evm_keys, NULL); - if (status) - goto fail1; + error = sparse_keymap_setup(input, dm355evm_keys, NULL); + if (error) + return error; /* REVISIT: flush the event queue? */ - status = request_threaded_irq(keys->irq, NULL, dm355evm_keys_irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - dev_name(&pdev->dev), keys); - if (status < 0) - goto fail2; - - /* register */ - status = input_register_device(input); - if (status < 0) - goto fail3; - - platform_set_drvdata(pdev, keys); - - return 0; - -fail3: - free_irq(keys->irq, keys); -fail2: - sparse_keymap_free(input); -fail1: - input_free_device(input); - kfree(keys); - dev_err(&pdev->dev, "can't register, err %d\n", status); - - return status; -} + /* set up "threaded IRQ handler" */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; -static int dm355evm_keys_remove(struct platform_device *pdev) -{ - struct dm355evm_keys *keys = platform_get_drvdata(pdev); + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, dm355evm_keys_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&pdev->dev), keys); + if (error) + return error; - free_irq(keys->irq, keys); - sparse_keymap_free(keys->input); - input_unregister_device(keys->input); - kfree(keys); + /* register */ + error = input_register_device(input); + if (error) + return error; return 0; } @@ -259,7 +233,6 @@ static int dm355evm_keys_remove(struct platform_device *pdev) */ static struct platform_driver dm355evm_keys_driver = { .probe = dm355evm_keys_probe, - .remove = dm355evm_keys_remove, .driver = { .name = "dm355evm_keys", }, diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index fb089d36c0d6..17eb84ab4c0b 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -652,7 +652,6 @@ static const struct i2c_device_id drv260x_id[] = { }; MODULE_DEVICE_TABLE(i2c, drv260x_id); -#ifdef CONFIG_OF static const struct of_device_id drv260x_of_match[] = { { .compatible = "ti,drv2604", }, { .compatible = "ti,drv2604l", }, @@ -661,13 +660,12 @@ static const struct of_device_id drv260x_of_match[] = { { } }; MODULE_DEVICE_TABLE(of, drv260x_of_match); -#endif static struct i2c_driver drv260x_driver = { .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", - .of_match_table = of_match_ptr(drv260x_of_match), + .of_match_table = drv260x_of_match, .pm = &drv260x_pm_ops, }, .id_table = drv260x_id, diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 5113877153d7..7dd1c1fbe42a 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -10,19 +10,15 @@ * GNU General Public License for more details. */ -#include <linux/module.h> -#include <linux/kernel.h> #include <linux/errno.h> -#include <linux/platform_device.h> #include <linux/input.h> -#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> #include <linux/regmap.h> - -#define VIB_DRV 0x4A - -#define VIB_DRV_SEL_MASK 0xf8 -#define VIB_DRV_SEL_SHIFT 0x03 -#define VIB_DRV_EN_MANUAL_MASK 0xfc +#include <linux/slab.h> #define VIB_MAX_LEVEL_mV (3100) #define VIB_MIN_LEVEL_mV (1200) @@ -30,20 +26,48 @@ #define MAX_FF_SPEED 0xff +struct pm8xxx_regs { + unsigned int enable_addr; + unsigned int enable_mask; + + unsigned int drv_addr; + unsigned int drv_mask; + unsigned int drv_shift; + unsigned int drv_en_manual_mask; +}; + +static const struct pm8xxx_regs pm8058_regs = { + .drv_addr = 0x4A, + .drv_mask = 0xf8, + .drv_shift = 3, + .drv_en_manual_mask = 0xfc, +}; + +static struct pm8xxx_regs pm8916_regs = { + .enable_addr = 0xc046, + .enable_mask = BIT(7), + .drv_addr = 0xc041, + .drv_mask = 0x1F, + .drv_shift = 0, + .drv_en_manual_mask = 0, +}; + /** * struct pm8xxx_vib - structure to hold vibrator data * @vib_input_dev: input device supporting force feedback * @work: work structure to set the vibration parameters * @regmap: regmap for register read/write + * @regs: registers' info * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip - * @reg_vib_drv: VIB_DRV register value + * @reg_vib_drv: regs->drv_addr register value */ struct pm8xxx_vib { struct input_dev *vib_input_dev; struct work_struct work; struct regmap *regmap; + const struct pm8xxx_regs *regs; int speed; int level; bool active; @@ -59,18 +83,24 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) { int rc; unsigned int val = vib->reg_vib_drv; + const struct pm8xxx_regs *regs = vib->regs; if (on) - val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); + val |= (vib->level << regs->drv_shift) & regs->drv_mask; else - val &= ~VIB_DRV_SEL_MASK; + val &= ~regs->drv_mask; - rc = regmap_write(vib->regmap, VIB_DRV, val); + rc = regmap_write(vib->regmap, regs->drv_addr, val); if (rc < 0) return rc; vib->reg_vib_drv = val; - return 0; + + if (regs->enable_mask) + rc = regmap_update_bits(vib->regmap, regs->enable_addr, + on ? regs->enable_mask : 0, val); + + return rc; } /** @@ -80,10 +110,11 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) static void pm8xxx_work_handler(struct work_struct *work) { struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); + const struct pm8xxx_regs *regs = vib->regs; int rc; unsigned int val; - rc = regmap_read(vib->regmap, VIB_DRV, &val); + rc = regmap_read(vib->regmap, regs->drv_addr, &val); if (rc < 0) return; @@ -147,6 +178,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) struct input_dev *input_dev; int error; unsigned int val; + const struct pm8xxx_regs *regs; vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); if (!vib) @@ -163,16 +195,19 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) INIT_WORK(&vib->work, pm8xxx_work_handler); vib->vib_input_dev = input_dev; + regs = of_device_get_match_data(&pdev->dev); + /* operate in manual mode */ - error = regmap_read(vib->regmap, VIB_DRV, &val); + error = regmap_read(vib->regmap, regs->drv_addr, &val); if (error < 0) return error; - val &= ~VIB_DRV_EN_MANUAL_MASK; - error = regmap_write(vib->regmap, VIB_DRV, val); + val &= regs->drv_en_manual_mask; + error = regmap_write(vib->regmap, regs->drv_addr, val); if (error < 0) return error; + vib->regs = regs; vib->reg_vib_drv = val; input_dev->name = "pm8xxx_vib_ffmemless"; @@ -212,8 +247,9 @@ static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); static const struct of_device_id pm8xxx_vib_id_table[] = { - { .compatible = "qcom,pm8058-vib" }, - { .compatible = "qcom,pm8921-vib" }, + { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index e53801dbd560..edca0d737750 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/pwm.h> #include <linux/slab.h> #include <linux/workqueue.h> @@ -29,6 +30,7 @@ struct pwm_beeper { struct regulator *amplifier; struct work_struct work; unsigned long period; + unsigned int bell_frequency; bool suspended; bool amplifier_on; }; @@ -94,7 +96,7 @@ static int pwm_beeper_event(struct input_dev *input, switch (code) { case SND_BELL: - value = value ? 1000 : 0; + value = value ? beeper->bell_frequency : 0; break; case SND_TONE: break; @@ -131,6 +133,7 @@ static int pwm_beeper_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pwm_beeper *beeper; struct pwm_state state; + u32 bell_frequency; int error; beeper = devm_kzalloc(dev, sizeof(*beeper), GFP_KERNEL); @@ -167,6 +170,16 @@ static int pwm_beeper_probe(struct platform_device *pdev) INIT_WORK(&beeper->work, pwm_beeper_work); + error = device_property_read_u32(dev, "beeper-hz", &bell_frequency); + if (error) { + bell_frequency = 1000; + dev_dbg(dev, + "failed to parse 'beeper-hz' property, using default: %uHz\n", + bell_frequency); + } + + beeper->bell_frequency = bell_frequency; + beeper->input = devm_input_allocate_device(dev); if (!beeper->input) { dev_err(dev, "Failed to allocate input device\n"); diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index ddb2f22fca7a..f210a3322559 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -20,13 +20,6 @@ #include <linux/gpio.h> #include <linux/platform_device.h> -/* - * Definition of buttons on the tablet. The ACPI index of each button - * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC - * Platforms" - */ -#define MAX_NBUTTONS 5 - struct soc_button_info { const char *name; int acpi_index; @@ -55,7 +48,7 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index) struct gpio_desc *desc; int gpio; - desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS); + desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); if (IS_ERR(desc)) return PTR_ERR(desc); @@ -79,14 +72,19 @@ soc_button_device_create(struct platform_device *pdev, int gpio; int error; + for (info = button_info; info->name; info++) + if (info->autorepeat == autorepeat) + n_buttons++; + gpio_keys_pdata = devm_kzalloc(&pdev->dev, sizeof(*gpio_keys_pdata) + - sizeof(*gpio_keys) * MAX_NBUTTONS, + sizeof(*gpio_keys) * n_buttons, GFP_KERNEL); if (!gpio_keys_pdata) return ERR_PTR(-ENOMEM); gpio_keys = (void *)(gpio_keys_pdata + 1); + n_buttons = 0; for (info = button_info; info->name; info++) { if (info->autorepeat != autorepeat) @@ -140,6 +138,153 @@ err_free_mem: return ERR_PTR(error); } +static int soc_button_get_acpi_object_int(const union acpi_object *obj) +{ + if (obj->type != ACPI_TYPE_INTEGER) + return -1; + + return obj->integer.value; +} + +/* Parse a single ACPI0011 _DSD button descriptor */ +static int soc_button_parse_btn_desc(struct device *dev, + const union acpi_object *desc, + int collection_uid, + struct soc_button_info *info) +{ + int upage, usage; + + if (desc->type != ACPI_TYPE_PACKAGE || + desc->package.count != 5 || + /* First byte should be 1 (control) */ + soc_button_get_acpi_object_int(&desc->package.elements[0]) != 1 || + /* Third byte should be collection uid */ + soc_button_get_acpi_object_int(&desc->package.elements[2]) != + collection_uid) { + dev_err(dev, "Invalid ACPI Button Descriptor\n"); + return -ENODEV; + } + + info->event_type = EV_KEY; + info->acpi_index = + soc_button_get_acpi_object_int(&desc->package.elements[1]); + upage = soc_button_get_acpi_object_int(&desc->package.elements[3]); + usage = soc_button_get_acpi_object_int(&desc->package.elements[4]); + + /* + * The UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e descriptors use HID + * usage page and usage codes, but otherwise the device is not HID + * compliant: it uses one irq per button instead of generating HID + * input reports and some buttons should generate wakeups where as + * others should not, so we cannot use the HID subsystem. + * + * Luckily all devices only use a few usage page + usage combinations, + * so we can simply check for the known combinations here. + */ + if (upage == 0x01 && usage == 0x81) { + info->name = "power"; + info->event_code = KEY_POWER; + info->wakeup = true; + } else if (upage == 0x07 && usage == 0xe3) { + info->name = "home"; + info->event_code = KEY_LEFTMETA; + info->wakeup = true; + } else if (upage == 0x0c && usage == 0xe9) { + info->name = "volume_up"; + info->event_code = KEY_VOLUMEUP; + info->autorepeat = true; + } else if (upage == 0x0c && usage == 0xea) { + info->name = "volume_down"; + info->event_code = KEY_VOLUMEDOWN; + info->autorepeat = true; + } else { + dev_warn(dev, "Unknown button index %d upage %02x usage %02x, ignoring\n", + info->acpi_index, upage, usage); + info->name = "unknown"; + info->event_code = KEY_RESERVED; + } + + return 0; +} + +/* ACPI0011 _DSD btns descriptors UUID: fa6bd625-9ce8-470d-a2c7-b3ca36c4282e */ +static const u8 btns_desc_uuid[16] = { + 0x25, 0xd6, 0x6b, 0xfa, 0xe8, 0x9c, 0x0d, 0x47, + 0xa2, 0xc7, 0xb3, 0xca, 0x36, 0xc4, 0x28, 0x2e +}; + +/* Parse ACPI0011 _DSD button descriptors */ +static struct soc_button_info *soc_button_get_button_info(struct device *dev) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + const union acpi_object *desc, *el0, *uuid, *btns_desc = NULL; + struct soc_button_info *button_info; + acpi_status status; + int i, btn, collection_uid = -1; + + status = acpi_evaluate_object_typed(ACPI_HANDLE(dev), "_DSD", NULL, + &buf, ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) { + dev_err(dev, "ACPI _DSD object not found\n"); + return ERR_PTR(-ENODEV); + } + + /* Look for the Button Descriptors UUID */ + desc = buf.pointer; + for (i = 0; (i + 1) < desc->package.count; i += 2) { + uuid = &desc->package.elements[i]; + + if (uuid->type != ACPI_TYPE_BUFFER || + uuid->buffer.length != 16 || + desc->package.elements[i + 1].type != ACPI_TYPE_PACKAGE) { + break; + } + + if (memcmp(uuid->buffer.pointer, btns_desc_uuid, 16) == 0) { + btns_desc = &desc->package.elements[i + 1]; + break; + } + } + + if (!btns_desc) { + dev_err(dev, "ACPI Button Descriptors not found\n"); + return ERR_PTR(-ENODEV); + } + + /* The first package describes the collection */ + el0 = &btns_desc->package.elements[0]; + if (el0->type == ACPI_TYPE_PACKAGE && + el0->package.count == 5 && + /* First byte should be 0 (collection) */ + soc_button_get_acpi_object_int(&el0->package.elements[0]) == 0 && + /* Third byte should be 0 (top level collection) */ + soc_button_get_acpi_object_int(&el0->package.elements[2]) == 0) { + collection_uid = soc_button_get_acpi_object_int( + &el0->package.elements[1]); + } + if (collection_uid == -1) { + dev_err(dev, "Invalid Button Collection Descriptor\n"); + return ERR_PTR(-ENODEV); + } + + /* There are package.count - 1 buttons + 1 terminating empty entry */ + button_info = devm_kcalloc(dev, btns_desc->package.count, + sizeof(*button_info), GFP_KERNEL); + if (!button_info) + return ERR_PTR(-ENOMEM); + + /* Parse the button descriptors */ + for (i = 1, btn = 0; i < btns_desc->package.count; i++, btn++) { + if (soc_button_parse_btn_desc(dev, + &btns_desc->package.elements[i], + collection_uid, + &button_info[btn])) + return ERR_PTR(-ENODEV); + } + + return button_info; +} + static int soc_button_remove(struct platform_device *pdev) { struct soc_button_data *priv = platform_get_drvdata(pdev); @@ -167,9 +312,15 @@ static int soc_button_probe(struct platform_device *pdev) if (!id) return -ENODEV; - button_info = (struct soc_button_info *)id->driver_data; + if (!id->driver_data) { + button_info = soc_button_get_button_info(dev); + if (IS_ERR(button_info)) + return PTR_ERR(button_info); + } else { + button_info = (struct soc_button_info *)id->driver_data; + } - if (gpiod_count(dev, KBUILD_MODNAME) <= 0) { + if (gpiod_count(dev, NULL) <= 0) { dev_dbg(dev, "no GPIO attached, ignoring...\n"); return -ENODEV; } @@ -197,9 +348,17 @@ static int soc_button_probe(struct platform_device *pdev) if (!priv->children[0] && !priv->children[1]) return -ENODEV; + if (!id->driver_data) + devm_kfree(dev, button_info); + return 0; } +/* + * Definition of buttons on the tablet. The ACPI index of each button + * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC + * Platforms" + */ static struct soc_button_info soc_button_PNP0C40[] = { { "power", 0, EV_KEY, KEY_POWER, false, true }, { "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, @@ -211,6 +370,7 @@ static struct soc_button_info soc_button_PNP0C40[] = { static const struct acpi_device_id soc_button_acpi_match[] = { { "PNP0C40", (unsigned long)soc_button_PNP0C40 }, + { "ACPI0011", 0 }, { } }; diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 54162d2cbcfc..1c13005b228f 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -64,13 +64,12 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev) return -ENOMEM; } - pwr->evbit[0] = BIT_MASK(EV_KEY); - pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + input_set_capability(pwr, EV_KEY, KEY_POWER); pwr->name = "twl4030_pwrbutton"; pwr->phys = "twl4030_pwrbutton/input0"; pwr->dev.parent = &pdev->dev; - err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq, + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, powerbutton_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_pwrbutton", pwr); diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index e25f87ba19f6..43e67f546366 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -1243,12 +1243,10 @@ static int setup_input_dev(void) error = input_register_polled_device(wistron_idev); if (error) - goto err_free_keymap; + goto err_free_dev; return 0; - err_free_keymap: - sparse_keymap_free(input_dev); err_free_dev: input_free_polled_device(wistron_idev); return error; @@ -1300,7 +1298,6 @@ static int wistron_remove(struct platform_device *dev) { wistron_led_remove(); input_unregister_polled_device(wistron_idev); - sparse_keymap_free(wistron_idev->input); input_free_polled_device(wistron_idev); bios_detach(); diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 3900875dec10..690148f9940e 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -41,6 +41,12 @@ struct xenkbd_info { char phys[32]; }; +enum { KPARAM_X, KPARAM_Y, KPARAM_CNT }; +static int ptr_size[KPARAM_CNT] = { XENFB_WIDTH, XENFB_HEIGHT }; +module_param_array(ptr_size, int, NULL, 0444); +MODULE_PARM_DESC(ptr_size, + "Pointing device width, height in pixels (default 800,600)"); + static int xenkbd_remove(struct xenbus_device *); static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); static void xenkbd_disconnect_backend(struct xenkbd_info *); @@ -84,8 +90,8 @@ static irqreturn_t input_handler(int rq, void *dev_id) input_report_key(dev, event->key.keycode, event->key.pressed); else - pr_warning("unhandled keycode 0x%x\n", - event->key.keycode); + pr_warn("unhandled keycode 0x%x\n", + event->key.keycode); break; case XENKBD_TYPE_POS: input_report_abs(dev, ABS_X, event->pos.abs_x); @@ -128,12 +134,17 @@ static int xenkbd_probe(struct xenbus_device *dev, if (!info->page) goto error_nomem; + /* Set input abs params to match backend screen res */ abs = xenbus_read_unsigned(dev->otherend, "feature-abs-pointer", 0); + ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, "width", + ptr_size[KPARAM_X]); + ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, "height", + ptr_size[KPARAM_Y]); if (abs) { ret = xenbus_write(XBT_NIL, dev->nodename, "request-abs-pointer", "1"); if (ret) { - pr_warning("xenkbd: can't request abs-pointer"); + pr_warn("xenkbd: can't request abs-pointer\n"); abs = 0; } } @@ -174,8 +185,8 @@ static int xenkbd_probe(struct xenbus_device *dev, if (abs) { __set_bit(EV_ABS, ptr->evbit); - input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); - input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + input_set_abs_params(ptr, ABS_X, 0, ptr_size[KPARAM_X], 0, 0); + input_set_abs_params(ptr, ABS_Y, 0, ptr_size[KPARAM_Y], 0, 0); } else { input_set_capability(ptr, EV_REL, REL_X); input_set_capability(ptr, EV_REL, REL_Y); @@ -309,9 +320,6 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info) static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { - struct xenkbd_info *info = dev_get_drvdata(&dev->dev); - int ret, val; - switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: @@ -321,15 +329,6 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, break; case XenbusStateInitWait: -InitWait: - if (xenbus_read_unsigned(info->xbdev->otherend, - "feature-abs-pointer", 0)) { - ret = xenbus_write(XBT_NIL, info->xbdev->nodename, - "request-abs-pointer", "1"); - if (ret) - pr_warning("xenkbd: can't request abs-pointer"); - } - xenbus_switch_state(dev, XenbusStateConnected); break; @@ -340,17 +339,7 @@ InitWait: * get Connected twice here. */ if (dev->state != XenbusStateConnected) - goto InitWait; /* no InitWait seen yet, fudge it */ - - /* Set input abs params to match backend screen res */ - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "width", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); - - if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, - "height", "%d", &val) > 0) - input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); - + xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosed: diff --git a/drivers/input/misc/yealink.h b/drivers/input/misc/yealink.h index 1e0f52397010..934c247f8a0f 100644 --- a/drivers/input/misc/yealink.h +++ b/drivers/input/misc/yealink.h @@ -28,7 +28,7 @@ struct yld_ctl_packet { u8 cmd; /* command code, see below */ u8 size; /* 1-11, size of used data bytes. */ - u16 offset; /* internal packet offset */ + __be16 offset; /* internal packet offset */ u8 data[11]; s8 sum; /* negative sum of 15 preceding bytes */ } __attribute__ ((packed)); diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 096abb4ad5cd..89ebb8f39fee 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -78,6 +78,18 @@ config MOUSE_PS2_SYNAPTICS If unsure, say Y. +config MOUSE_PS2_SYNAPTICS_SMBUS + bool "Synaptics PS/2 SMbus companion" if EXPERT + default y + depends on MOUSE_PS2 + depends on I2C=y || I2C=MOUSE_PS2 + select MOUSE_PS2_SMBUS + help + Say Y here if you have a Synaptics RMI4 touchpad connected to + to an SMBus, but enumerated through PS/2. + + If unsure, say Y. + config MOUSE_PS2_CYPRESS bool "Cypress PS/2 mouse protocol extension" if EXPERT default y @@ -171,6 +183,10 @@ config MOUSE_PS2_VMMOUSE If unsure, say N. +config MOUSE_PS2_SMBUS + bool + depends on MOUSE_PS2 + config MOUSE_SERIAL tristate "Serial mouse" select SERIO diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 6168b134937b..56bf0ad877c6 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -39,6 +39,8 @@ psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o psmouse-$(CONFIG_MOUSE_PS2_VMMOUSE) += vmmouse.o +psmouse-$(CONFIG_MOUSE_PS2_SMBUS) += psmouse-smbus.o + elan_i2c-objs := elan_i2c_core.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_SMBUS) += elan_i2c_smbus.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index f210e19ddba6..262d1057c1da 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -106,39 +106,36 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = { #define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ - { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ - { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ - { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ - { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ - /* * XXX This entry is suspicious. First byte has zero lower nibble, * which is what a normal mouse would report. Also, the value 0x0e * isn't valid per PS/2 spec. */ - { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - - { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ - { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, - { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ - { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ - { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, + { { 0x20, 0x02, 0x0e }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + + { { 0x22, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, + { { 0x22, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ + { { 0x32, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ + { { 0x33, 0x02, 0x0a }, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ + { { 0x52, 0x01, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ - { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } }, + { { 0x53, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x53, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x60, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ + { { 0x62, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xcf, 0xcf, + ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ + { { 0x63, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x02, 0x28 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x64 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x63, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ + { { 0x73, 0x00, 0x14 }, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ + { { 0x73, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, + { { 0x73, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ }; static const struct alps_protocol_info alps_v3_protocol_data = { @@ -149,6 +146,10 @@ static const struct alps_protocol_info alps_v3_rushmore_data = { ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT }; +static const struct alps_protocol_info alps_v4_protocol_data = { + ALPS_PROTO_V4, 0x8f, 0x8f, 0 +}; + static const struct alps_protocol_info alps_v5_protocol_data = { ALPS_PROTO_V5, 0xc8, 0xd8, 0 }; @@ -161,6 +162,10 @@ static const struct alps_protocol_info alps_v8_protocol_data = { ALPS_PROTO_V8, 0x18, 0x18, 0 }; +static const struct alps_protocol_info alps_v9_protocol_data = { + ALPS_PROTO_V9, 0xc8, 0xc8, 0 +}; + /* * Some v2 models report the stick buttons in separate bits */ @@ -2806,12 +2811,8 @@ static const struct alps_protocol_info *alps_match_table(unsigned char *e7, for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { model = &alps_model_data[i]; - if (!memcmp(e7, model->signature, sizeof(model->signature)) && - (!model->command_mode_resp || - model->command_mode_resp == ec[2])) { - + if (!memcmp(e7, model->signature, sizeof(model->signature))) return &model->protocol_info; - } } return NULL; @@ -2849,7 +2850,10 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) protocol = alps_match_table(e7, ec); if (!protocol) { - if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && + if (e7[0] == 0x73 && e7[1] == 0x02 && e7[2] == 0x64 && + ec[2] == 0x8a) { + protocol = &alps_v4_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { protocol = &alps_v5_protocol_data; } else if (ec[0] == 0x88 && @@ -2863,6 +2867,12 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) } else if (e7[0] == 0x73 && e7[1] == 0x03 && (e7[2] == 0x14 || e7[2] == 0x28)) { protocol = &alps_v8_protocol_data; + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) { + protocol = &alps_v9_protocol_data; + psmouse_warn(psmouse, + "Unsupported ALPS V9 touchpad: E7=%3ph, EC=%3ph\n", + e7, ec); + return -EINVAL; } else { psmouse_dbg(psmouse, "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 4334f2805d93..ed2d6879fa52 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -23,6 +23,7 @@ #define ALPS_PROTO_V6 0x600 #define ALPS_PROTO_V7 0x700 /* t3btl t4s */ #define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ +#define ALPS_PROTO_V9 0x900 /* ss3btl */ #define MAX_TOUCHES 4 @@ -172,10 +173,6 @@ struct alps_protocol_info { /** * struct alps_model_info - touchpad ID table * @signature: E7 response string to match. - * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response - * (aka command mode response) identifies the firmware minor version. This - * can be used to distinguish different hardware models which are not - * uniquely identifiable through their E7 responses. * @protocol_info: information about protocol used by the device. * * Many (but not all) ALPS touchpads can be identified by looking at the @@ -184,7 +181,6 @@ struct alps_protocol_info { */ struct alps_model_info { u8 signature[3]; - u8 command_mode_resp; struct alps_protocol_info protocol_info; }; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index a598b7223cef..f73b47b8c578 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -116,17 +116,6 @@ static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; -struct psmouse_protocol { - enum psmouse_type type; - bool maxproto; - bool ignore_parity; /* Protocol should ignore parity errors from KBC */ - bool try_passthru; /* Try protocol also on passthrough ports */ - const char *name; - const char *alias; - int (*detect)(struct psmouse *, bool); - int (*init)(struct psmouse *); -}; - static void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) { input_report_key(dev, BTN_LEFT, buttons & BIT(0)); @@ -148,7 +137,7 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) /* Full packet accumulated, process it */ - switch (psmouse->type) { + switch (psmouse->protocol->type) { case PSMOUSE_IMPS: /* IntelliMouse has scroll wheel */ input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); @@ -325,7 +314,8 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; if (unlikely((flags & SERIO_TIMEOUT) || - ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { + ((flags & SERIO_PARITY) && + !psmouse->protocol->ignore_parity))) { if (psmouse->state == PSMOUSE_ACTIVATED) psmouse_warn(psmouse, @@ -372,7 +362,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, } if (psmouse->packet[1] == PSMOUSE_RET_ID || - (psmouse->type == PSMOUSE_HGPK && + (psmouse->protocol->type == PSMOUSE_HGPK && psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); @@ -783,7 +773,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "SynPS/2", .alias = "synaptics", .detect = synaptics_detect, - .init = synaptics_init, + .init = synaptics_init_absolute, }, { .type = PSMOUSE_SYNAPTICS_RELATIVE, @@ -793,6 +783,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .init = synaptics_init_relative, }, #endif +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + { + .type = PSMOUSE_SYNAPTICS_SMBUS, + .name = "SynSMBus", + .alias = "synaptics-smbus", + .detect = synaptics_detect, + .init = synaptics_init_smbus, + .smbus_companion = true, + }, +#endif #ifdef CONFIG_MOUSE_PS2_ALPS { .type = PSMOUSE_ALPS, @@ -959,6 +959,8 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + psmouse->protocol = &psmouse_protocols[0]; + psmouse->set_rate = psmouse_set_rate; psmouse->set_resolution = psmouse_set_resolution; psmouse->set_scale = psmouse_set_scale; @@ -966,6 +968,7 @@ static void psmouse_apply_defaults(struct psmouse *psmouse) psmouse->protocol_handler = psmouse_process_byte; psmouse->pktsize = 3; psmouse->reconnect = NULL; + psmouse->fast_reconnect = NULL; psmouse->disconnect = NULL; psmouse->cleanup = NULL; psmouse->pt_activate = NULL; @@ -1018,6 +1021,7 @@ static int psmouse_extensions(struct psmouse *psmouse, unsigned int max_proto, bool set_properties) { bool synaptics_hardware = false; + int ret; /* * Always check for focaltech, this is safe as it uses pnp-id @@ -1080,9 +1084,14 @@ static int psmouse_extensions(struct psmouse *psmouse, * enabled first, since we try detecting Synaptics * even when protocol is disabled. */ - if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && - (!set_properties || synaptics_init(psmouse) == 0)) { - return PSMOUSE_SYNAPTICS; + if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) || + IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS)) { + if (!set_properties) + return PSMOUSE_SYNAPTICS; + + ret = synaptics_init(psmouse); + if (ret >= 0) + return ret; } /* @@ -1431,9 +1440,8 @@ static void psmouse_cleanup(struct serio *serio) */ static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse, *parent = NULL; - - psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *parent = NULL; sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); @@ -1461,7 +1469,10 @@ static void psmouse_disconnect(struct serio *serio) serio_close(serio); serio_set_drvdata(serio, NULL); - input_unregister_device(psmouse->dev); + + if (psmouse->dev) + input_unregister_device(psmouse->dev); + kfree(psmouse); if (parent) @@ -1475,6 +1486,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, { const struct psmouse_protocol *selected_proto; struct input_dev *input_dev = psmouse->dev; + enum psmouse_type type; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; @@ -1487,15 +1499,13 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, if (proto->init && proto->init(psmouse) < 0) return -1; - psmouse->type = proto->type; selected_proto = proto; } else { - psmouse->type = psmouse_extensions(psmouse, - psmouse_max_proto, true); - selected_proto = psmouse_protocol_by_type(psmouse->type); + type = psmouse_extensions(psmouse, psmouse_max_proto, true); + selected_proto = psmouse_protocol_by_type(type); } - psmouse->ignore_parity = selected_proto->ignore_parity; + psmouse->protocol = selected_proto; /* * If mouse's packet size is 3 there is no point in polling the @@ -1521,7 +1531,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, input_dev->phys = psmouse->phys; input_dev->id.bustype = BUS_I8042; input_dev->id.vendor = 0x0002; - input_dev->id.product = psmouse->type; + input_dev->id.product = psmouse->protocol->type; input_dev->id.version = psmouse->model; return 0; @@ -1583,12 +1593,18 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_switch_protocol(psmouse, NULL); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); - error = input_register_device(psmouse->dev); - if (error) - goto err_protocol_disconnect; + error = input_register_device(input_dev); + if (error) + goto err_protocol_disconnect; + } else { + /* Smbus companion will be reporting events, not us. */ + input_free_device(input_dev); + psmouse->dev = input_dev = NULL; + } if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -1597,7 +1613,12 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (error) goto err_pt_deactivate; - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); out: /* If this is a pass-through port the parent needs to be re-activated */ @@ -1610,8 +1631,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) err_pt_deactivate: if (parent && parent->pt_deactivate) parent->pt_deactivate(parent); - input_unregister_device(psmouse->dev); - input_dev = NULL; /* so we don't try to free it below */ + if (input_dev) { + input_unregister_device(input_dev); + input_dev = NULL; /* so we don't try to free it below */ + } err_protocol_disconnect: if (psmouse->disconnect) psmouse->disconnect(psmouse); @@ -1628,15 +1651,26 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto out; } -static int psmouse_reconnect(struct serio *serio) +static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) { struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; - unsigned char type; + int (*reconnect_handler)(struct psmouse *); + enum psmouse_type type; int rc = -1; mutex_lock(&psmouse_mutex); + if (fast_reconnect) { + reconnect_handler = psmouse->fast_reconnect; + if (!reconnect_handler) { + rc = -ENOENT; + goto out_unlock; + } + } else { + reconnect_handler = psmouse->reconnect; + } + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { parent = serio_get_drvdata(serio->parent); psmouse_deactivate(parent); @@ -1644,8 +1678,8 @@ static int psmouse_reconnect(struct serio *serio) psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - if (psmouse->reconnect) { - if (psmouse->reconnect(psmouse)) + if (reconnect_handler) { + if (reconnect_handler(psmouse)) goto out; } else { psmouse_reset(psmouse); @@ -1654,7 +1688,7 @@ static int psmouse_reconnect(struct serio *serio) goto out; type = psmouse_extensions(psmouse, psmouse_max_proto, false); - if (psmouse->type != type) + if (psmouse->protocol->type != type) goto out; } @@ -1662,14 +1696,21 @@ static int psmouse_reconnect(struct serio *serio) * OK, the device type (and capabilities) match the old one, * we can continue using it, complete initialization */ - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - psmouse_initialize(psmouse); + if (!psmouse->protocol->smbus_companion) { + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); + } if (parent && parent->pt_activate) parent->pt_activate(parent); - psmouse_activate(psmouse); + /* + * PS/2 devices having SMBus companions should stay disabled + * on PS/2 side, in order to have SMBus part operable. + */ + if (!psmouse->protocol->smbus_companion) + psmouse_activate(psmouse); + rc = 0; out: @@ -1677,10 +1718,21 @@ out: if (parent) psmouse_activate(parent); +out_unlock: mutex_unlock(&psmouse_mutex); return rc; } +static int psmouse_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, false); +} + +static int psmouse_fast_reconnect(struct serio *serio) +{ + return __psmouse_reconnect(serio, true); +} + static struct serio_device_id psmouse_serio_ids[] = { { .type = SERIO_8042, @@ -1708,6 +1760,7 @@ static struct serio_driver psmouse_drv = { .interrupt = psmouse_interrupt, .connect = psmouse_connect, .reconnect = psmouse_reconnect, + .fast_reconnect = psmouse_fast_reconnect, .disconnect = psmouse_disconnect, .cleanup = psmouse_cleanup, }; @@ -1717,9 +1770,11 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de { struct serio *serio = to_serio_port(dev); struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse; + struct psmouse *psmouse = serio_get_drvdata(serio); - psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) + return -ENOENT; return attr->show(psmouse, attr->data, buf); } @@ -1738,6 +1793,12 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse = serio_get_drvdata(serio); + if (psmouse->protocol->smbus_companion && + devattr != &psmouse_attr_protocol.dattr) { + retval = -ENOENT; + goto out_unlock; + } + if (attr->protect) { if (psmouse->state == PSMOUSE_IGNORE) { retval = -ENODEV; @@ -1749,13 +1810,14 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev psmouse_deactivate(parent); } - psmouse_deactivate(psmouse); + if (!psmouse->protocol->smbus_companion) + psmouse_deactivate(psmouse); } retval = attr->set(psmouse, attr->data, buf, count); if (attr->protect) { - if (retval != -ENODEV) + if (retval != -ENODEV && !psmouse->protocol->smbus_companion) psmouse_activate(psmouse); if (parent) @@ -1792,7 +1854,7 @@ static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) { - return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); + return sprintf(buf, "%s\n", psmouse->protocol->name); } static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) @@ -1808,7 +1870,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!proto) return -EINVAL; - if (psmouse->type == proto->type) + if (psmouse->protocol == proto) return count; new_dev = input_allocate_device(); @@ -1832,7 +1894,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co return -ENODEV; } - if (psmouse->type == proto->type) { + if (psmouse->protocol == proto) { input_free_device(new_dev); return count; /* switched by other thread */ } @@ -1845,7 +1907,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co } old_dev = psmouse->dev; - old_proto = psmouse_protocol_by_type(psmouse->type); + old_proto = psmouse->protocol; if (psmouse->disconnect) psmouse->disconnect(psmouse); @@ -1864,23 +1926,29 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co psmouse_initialize(psmouse); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - error = input_register_device(psmouse->dev); - if (error) { - if (psmouse->disconnect) - psmouse->disconnect(psmouse); + if (psmouse->protocol->smbus_companion) { + input_free_device(psmouse->dev); + psmouse->dev = NULL; + } else { + error = input_register_device(psmouse->dev); + if (error) { + if (psmouse->disconnect) + psmouse->disconnect(psmouse); - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_free_device(new_dev); - psmouse->dev = old_dev; - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - psmouse_switch_protocol(psmouse, old_proto); - psmouse_initialize(psmouse); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_set_state(psmouse, PSMOUSE_IGNORE); + input_free_device(new_dev); + psmouse->dev = old_dev; + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + psmouse_switch_protocol(psmouse, old_proto); + psmouse_initialize(psmouse); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - return error; + return error; + } } - input_unregister_device(old_dev); + if (old_dev) + input_unregister_device(old_dev); if (parent && parent->pt_activate) parent->pt_activate(parent); @@ -1947,16 +2015,27 @@ static int __init psmouse_init(void) synaptics_module_init(); hgpk_module_init(); + err = psmouse_smbus_module_init(); + if (err) + return err; + kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); if (!kpsmoused_wq) { pr_err("failed to create kpsmoused workqueue\n"); - return -ENOMEM; + err = -ENOMEM; + goto err_smbus_exit; } err = serio_register_driver(&psmouse_drv); if (err) - destroy_workqueue(kpsmoused_wq); + goto err_destroy_wq; + + return 0; +err_destroy_wq: + destroy_workqueue(kpsmoused_wq); +err_smbus_exit: + psmouse_smbus_module_exit(); return err; } @@ -1964,6 +2043,7 @@ static void __exit psmouse_exit(void) { serio_unregister_driver(&psmouse_drv); destroy_workqueue(kpsmoused_wq); + psmouse_smbus_module_exit(); } module_init(psmouse_init); diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c new file mode 100644 index 000000000000..c7ac24d119c1 --- /dev/null +++ b/drivers/input/mouse/psmouse-smbus.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2017 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/libps2.h> +#include <linux/i2c.h> +#include <linux/serio.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include "psmouse.h" + +struct psmouse_smbus_dev { + struct i2c_board_info board; + struct psmouse *psmouse; + struct i2c_client *client; + struct list_head node; + bool dead; +}; + +static LIST_HEAD(psmouse_smbus_list); +static DEFINE_MUTEX(psmouse_smbus_mutex); + +static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter) +{ + struct psmouse_smbus_dev *smbdev; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry(smbdev, &psmouse_smbus_list, node) { + if (smbdev->dead) + continue; + + if (smbdev->client) + continue; + + /* + * Here would be a good place to check if device is actually + * present, but it seems that SMBus will not respond unless we + * fully reset PS/2 connection. So cross our fingers, and try + * to switch over, hopefully our system will not have too many + * "host notify" I2C adapters. + */ + psmouse_dbg(smbdev->psmouse, + "SMBus candidate adapter appeared, triggering rescan\n"); + serio_rescan(smbdev->psmouse->ps2dev.serio); + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +static void psmouse_smbus_detach_i2c_client(struct i2c_client *client) +{ + struct psmouse_smbus_dev *smbdev, *tmp; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (smbdev->client != client) + continue; + + kfree(client->dev.platform_data); + client->dev.platform_data = NULL; + + if (!smbdev->dead) { + psmouse_dbg(smbdev->psmouse, + "Marking SMBus companion %s as gone\n", + dev_name(&smbdev->client->dev)); + smbdev->dead = true; + serio_rescan(smbdev->psmouse->ps2dev.serio); + } else { + list_del(&smbdev->node); + kfree(smbdev); + } + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +static int psmouse_smbus_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (dev->type == &i2c_adapter_type) + psmouse_smbus_check_adapter(to_i2c_adapter(dev)); + break; + + case BUS_NOTIFY_REMOVED_DEVICE: + if (dev->type == &i2c_client_type) + psmouse_smbus_detach_i2c_client(to_i2c_client(dev)); + break; + } + + return 0; +} + +static struct notifier_block psmouse_smbus_notifier = { + .notifier_call = psmouse_smbus_notifier_call, +}; + +static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse) +{ + return PSMOUSE_FULL_PACKET; +} + +static int psmouse_smbus_reconnect(struct psmouse *psmouse) +{ + psmouse_deactivate(psmouse); + + return 0; +} + +struct psmouse_smbus_removal_work { + struct work_struct work; + struct i2c_client *client; +}; + +static void psmouse_smbus_remove_i2c_device(struct work_struct *work) +{ + struct psmouse_smbus_removal_work *rwork = + container_of(work, struct psmouse_smbus_removal_work, work); + + dev_dbg(&rwork->client->dev, "destroying SMBus companion device\n"); + i2c_unregister_device(rwork->client); + + kfree(rwork); +} + +/* + * This schedules removal of SMBus companion device. We have to do + * it in a separate tread to avoid deadlocking on psmouse_mutex in + * case the device has a trackstick (which is also driven by psmouse). + * + * Note that this may be racing with i2c adapter removal, but we + * can't do anything about that: i2c automatically destroys clients + * attached to an adapter that is being removed. This has to be + * fixed in i2c core. + */ +static void psmouse_smbus_schedule_remove(struct i2c_client *client) +{ + struct psmouse_smbus_removal_work *rwork; + + rwork = kzalloc(sizeof(*rwork), GFP_KERNEL); + if (rwork) { + INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device); + rwork->client = client; + + schedule_work(&rwork->work); + } +} + +static void psmouse_smbus_disconnect(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev = psmouse->private; + + mutex_lock(&psmouse_smbus_mutex); + + if (smbdev->dead) { + list_del(&smbdev->node); + kfree(smbdev); + } else { + smbdev->dead = true; + psmouse_dbg(smbdev->psmouse, + "posting removal request for SMBus companion %s\n", + dev_name(&smbdev->client->dev)); + psmouse_smbus_schedule_remove(smbdev->client); + } + + mutex_unlock(&psmouse_smbus_mutex); + + psmouse->private = NULL; +} + +static int psmouse_smbus_create_companion(struct device *dev, void *data) +{ + struct psmouse_smbus_dev *smbdev = data; + unsigned short addr_list[] = { smbdev->board.addr, I2C_CLIENT_END }; + struct i2c_adapter *adapter; + + adapter = i2c_verify_adapter(dev); + if (!adapter) + return 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return 0; + + smbdev->client = i2c_new_probed_device(adapter, &smbdev->board, + addr_list, NULL); + if (!smbdev->client) + return 0; + + /* We have our(?) device, stop iterating i2c bus. */ + return 1; +} + +void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ + struct psmouse_smbus_dev *smbdev, *tmp; + + mutex_lock(&psmouse_smbus_mutex); + + list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) { + if (psmouse == smbdev->psmouse) { + list_del(&smbdev->node); + kfree(smbdev); + } + } + + mutex_unlock(&psmouse_smbus_mutex); +} + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs) +{ + struct psmouse_smbus_dev *smbdev; + int error; + + smbdev = kzalloc(sizeof(*smbdev), GFP_KERNEL); + if (!smbdev) + return -ENOMEM; + + smbdev->psmouse = psmouse; + smbdev->board = *board; + + smbdev->board.platform_data = kmemdup(pdata, pdata_size, GFP_KERNEL); + if (!smbdev->board.platform_data) { + kfree(smbdev); + return -ENOMEM; + } + + psmouse->private = smbdev; + psmouse->protocol_handler = psmouse_smbus_process_byte; + psmouse->reconnect = psmouse_smbus_reconnect; + psmouse->fast_reconnect = psmouse_smbus_reconnect; + psmouse->disconnect = psmouse_smbus_disconnect; + psmouse->resync_time = 0; + + psmouse_deactivate(psmouse); + + mutex_lock(&psmouse_smbus_mutex); + list_add_tail(&smbdev->node, &psmouse_smbus_list); + mutex_unlock(&psmouse_smbus_mutex); + + /* Bind to already existing adapters right away */ + error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion); + + if (smbdev->client) { + /* We have our companion device */ + return 0; + } + + /* + * If we did not create i2c device we will not need platform + * data even if we are leaving breadcrumbs. + */ + kfree(smbdev->board.platform_data); + smbdev->board.platform_data = NULL; + + if (error < 0 || !leave_breadcrumbs) { + mutex_lock(&psmouse_smbus_mutex); + list_del(&smbdev->node); + mutex_unlock(&psmouse_smbus_mutex); + + kfree(smbdev); + } + + return error < 0 ? error : -EAGAIN; +} + +int __init psmouse_smbus_module_init(void) +{ + int error; + + error = bus_register_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + if (error) { + pr_err("failed to register i2c bus notifier: %d\n", error); + return error; + } + + return 0; +} + +void psmouse_smbus_module_exit(void) +{ + bus_unregister_notifier(&i2c_bus_type, &psmouse_smbus_notifier); + flush_scheduled_work(); +} diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 8c83b8e2505c..38855e425f01 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -44,21 +44,60 @@ enum psmouse_scale { PSMOUSE_SCALE21 }; +enum psmouse_type { + PSMOUSE_NONE, + PSMOUSE_PS2, + PSMOUSE_PS2PP, + PSMOUSE_THINKPS, + PSMOUSE_GENPS, + PSMOUSE_IMPS, + PSMOUSE_IMEX, + PSMOUSE_SYNAPTICS, + PSMOUSE_ALPS, + PSMOUSE_LIFEBOOK, + PSMOUSE_TRACKPOINT, + PSMOUSE_TOUCHKIT_PS2, + PSMOUSE_CORTRON, + PSMOUSE_HGPK, + PSMOUSE_ELANTECH, + PSMOUSE_FSP, + PSMOUSE_SYNAPTICS_RELATIVE, + PSMOUSE_CYPRESS, + PSMOUSE_FOCALTECH, + PSMOUSE_VMMOUSE, + PSMOUSE_BYD, + PSMOUSE_SYNAPTICS_SMBUS, + PSMOUSE_AUTO /* This one should always be last */ +}; + +struct psmouse; + +struct psmouse_protocol { + enum psmouse_type type; + bool maxproto; + bool ignore_parity; /* Protocol should ignore parity errors from KBC */ + bool try_passthru; /* Try protocol also on passthrough ports */ + bool smbus_companion; /* "Protocol" is a stub, device is on SMBus */ + const char *name; + const char *alias; + int (*detect)(struct psmouse *, bool); + int (*init)(struct psmouse *); +}; + struct psmouse { void *private; struct input_dev *dev; struct ps2dev ps2dev; struct delayed_work resync_work; - char *vendor; - char *name; + const char *vendor; + const char *name; + const struct psmouse_protocol *protocol; unsigned char packet[8]; unsigned char badbyte; unsigned char pktcnt; unsigned char pktsize; - unsigned char type; unsigned char oob_data_type; unsigned char extra_buttons; - bool ignore_parity; bool acks_disable_command; unsigned int model; unsigned long last; @@ -80,6 +119,7 @@ struct psmouse { void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale); int (*reconnect)(struct psmouse *psmouse); + int (*fast_reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); void (*cleanup)(struct psmouse *psmouse); int (*poll)(struct psmouse *psmouse); @@ -88,31 +128,6 @@ struct psmouse { void (*pt_deactivate)(struct psmouse *psmouse); }; -enum psmouse_type { - PSMOUSE_NONE, - PSMOUSE_PS2, - PSMOUSE_PS2PP, - PSMOUSE_THINKPS, - PSMOUSE_GENPS, - PSMOUSE_IMPS, - PSMOUSE_IMEX, - PSMOUSE_SYNAPTICS, - PSMOUSE_ALPS, - PSMOUSE_LIFEBOOK, - PSMOUSE_TRACKPOINT, - PSMOUSE_TOUCHKIT_PS2, - PSMOUSE_CORTRON, - PSMOUSE_HGPK, - PSMOUSE_ELANTECH, - PSMOUSE_FSP, - PSMOUSE_SYNAPTICS_RELATIVE, - PSMOUSE_CYPRESS, - PSMOUSE_FOCALTECH, - PSMOUSE_VMMOUSE, - PSMOUSE_BYD, - PSMOUSE_AUTO /* This one should always be last */ -}; - void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, unsigned long delay); int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); @@ -195,5 +210,34 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ &(psmouse)->ps2dev.serio->dev, \ psmouse_fmt(format), ##__VA_ARGS__) +#ifdef CONFIG_MOUSE_PS2_SMBUS + +int psmouse_smbus_module_init(void); +void psmouse_smbus_module_exit(void); + +struct i2c_board_info; + +int psmouse_smbus_init(struct psmouse *psmouse, + const struct i2c_board_info *board, + const void *pdata, size_t pdata_size, + bool leave_breadcrumbs); +void psmouse_smbus_cleanup(struct psmouse *psmouse); + +#else /* !CONFIG_MOUSE_PS2_SMBUS */ + +static inline int psmouse_smbus_module_init(void) +{ + return 0; +} + +static inline void psmouse_smbus_module_exit(void) +{ +} + +static inline void psmouse_smbus_cleanup(struct psmouse *psmouse) +{ +} + +#endif /* CONFIG_MOUSE_PS2_SMBUS */ #endif /* _PSMOUSE_H */ diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 597ee4b01d9f..131df9d3660f 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -29,6 +29,8 @@ #include <linux/input/mt.h> #include <linux/serio.h> #include <linux/libps2.h> +#include <linux/rmi.h> +#include <linux/i2c.h> #include <linux/slab.h> #include "psmouse.h" #include "synaptics.h" @@ -77,22 +79,27 @@ /* * Set the synaptics touchpad mode byte by special commands */ -static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) +static int synaptics_mode_cmd(struct psmouse *psmouse, u8 mode) { - unsigned char param[1]; + u8 param[1]; + int error; + + error = psmouse_sliced_command(psmouse, mode); + if (error) + return error; - if (psmouse_sliced_command(psmouse, mode)) - return -1; param[0] = SYN_PS_SET_MODE2; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE); + if (error) + return error; + return 0; } int synaptics_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; + u8 param[4]; param[0] = 0; @@ -119,59 +126,8 @@ void synaptics_reset(struct psmouse *psmouse) synaptics_mode_cmd(psmouse, 0); } -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - -static bool cr48_profile_sensor; - -#define ANY_BOARD_ID 0 -struct min_max_quirk { - const char * const *pnp_ids; - struct { - unsigned long int min, max; - } board_id; - int x_min, x_max, y_min, y_max; -}; - -static const struct min_max_quirk min_max_pnpid_table[] = { - { - (const char * const []){"LEN0033", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5052, 2258, 4832 - }, - { - (const char * const []){"LEN0042", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1232, 5710, 1156, 4696 - }, - { - (const char * const []){"LEN0034", "LEN0036", "LEN0037", - "LEN0039", "LEN2002", "LEN2004", - NULL}, - {ANY_BOARD_ID, 2961}, - 1024, 5112, 2024, 4832 - }, - { - (const char * const []){"LEN2000", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5113, 2021, 4832 - }, - { - (const char * const []){"LEN2001", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5022, 2508, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {2691, 2691}, - 1024, 5045, 2457, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1264, 5675, 1171, 4688 - }, - { } -}; +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) /* This list has been kindly provided by Synaptics. */ static const char * const topbuttonpad_pnp_ids[] = { @@ -211,101 +167,109 @@ static const char * const topbuttonpad_pnp_ids[] = { NULL }; -/* This list has been kindly provided by Synaptics. */ -static const char * const forcepad_pnp_ids[] = { - "SYN300D", - "SYN3014", +static const char * const smbus_pnp_ids[] = { + /* all of the topbuttonpad_pnp_ids are valid, we just add some extras */ + "LEN0048", /* X1 Carbon 3 */ + "LEN0046", /* X250 */ + "LEN004a", /* W541 */ + "LEN200f", /* T450s */ NULL }; -/***************************************************************************** - * Synaptics communications functions - ****************************************************************************/ - /* - * Synaptics touchpads report the y coordinate from bottom to top, which is - * opposite from what userspace expects. - * This function is used to invert y before reporting. + * Send a command to the synpatics touchpad by special commands */ -static int synaptics_invert_y(int y) +static int synaptics_send_cmd(struct psmouse *psmouse, u8 cmd, u8 *param) { - return YMAX_NOMINAL + YMIN_NOMINAL - y; + int error; + + error = psmouse_sliced_command(psmouse, cmd); + if (error) + return error; + + error = ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO); + if (error) + return error; + + return 0; +} + +static int synaptics_query_int(struct psmouse *psmouse, u8 query_cmd, u32 *val) +{ + int error; + union { + __be32 be_val; + char buf[4]; + } resp = { 0 }; + + error = synaptics_send_cmd(psmouse, query_cmd, resp.buf + 1); + if (error) + return error; + + *val = be32_to_cpu(resp.be_val); + return 0; } /* - * Send a command to the synpatics touchpad by special commands + * Identify Touchpad + * See also the SYN_ID_* macros */ -static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) +static int synaptics_identify(struct psmouse *psmouse, + struct synaptics_device_info *info) { - if (psmouse_sliced_command(psmouse, c)) - return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - return 0; + int error; + + error = synaptics_query_int(psmouse, SYN_QUE_IDENTIFY, &info->identity); + if (error) + return error; + + return SYN_ID_IS_SYNAPTICS(info->identity) ? 0 : -ENXIO; } /* * Read the model-id bytes from the touchpad * see also SYN_MODEL_* macros */ -static int synaptics_model_id(struct psmouse *psmouse) +static int synaptics_model_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; - unsigned char mi[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) - return -1; - priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; - return 0; + return synaptics_query_int(psmouse, SYN_QUE_MODEL, &info->model_id); } -static int synaptics_more_extended_queries(struct psmouse *psmouse) +/* + * Read the firmware id from the touchpad + */ +static int synaptics_firmware_id(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; - unsigned char buf[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf)) - return -1; - - priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2]; - - return 0; + return synaptics_query_int(psmouse, SYN_QUE_FIRMWARE_ID, + &info->firmware_id); } /* * Read the board id and the "More Extended Queries" from the touchpad * The board id is encoded in the "QUERY MODES" response */ -static int synaptics_query_modes(struct psmouse *psmouse) +static int synaptics_query_modes(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; - unsigned char bid[3]; + u8 bid[3]; + int error; /* firmwares prior 7.5 have no board_id encoded */ - if (SYN_ID_FULL(priv->identity) < 0x705) + if (SYN_ID_FULL(info->identity) < 0x705) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid)) - return -1; - priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; - - if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse); + error = synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid); + if (error) + return error; - return 0; -} + info->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; -/* - * Read the firmware id from the touchpad - */ -static int synaptics_firmware_id(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char fwid[3]; + if (SYN_MEXT_CAP_BIT(bid[0])) + return synaptics_query_int(psmouse, SYN_QUE_MEXT_CAPAB_10, + &info->ext_cap_10); - if (synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid)) - return -1; - priv->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; return 0; } @@ -313,139 +277,236 @@ static int synaptics_firmware_id(struct psmouse *psmouse) * Read the capability-bits from the touchpad * see also the SYN_CAP_* macros */ -static int synaptics_capability(struct psmouse *psmouse) +static int synaptics_capability(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; - unsigned char cap[3]; + int error; - if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) - return -1; - priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - priv->ext_cap = priv->ext_cap_0c = 0; + error = synaptics_query_int(psmouse, SYN_QUE_CAPABILITIES, + &info->capabilities); + if (error) + return error; + + info->ext_cap = info->ext_cap_0c = 0; /* * Older firmwares had submodel ID fixed to 0x47 */ - if (SYN_ID_FULL(priv->identity) < 0x705 && - SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) { - return -1; + if (SYN_ID_FULL(info->identity) < 0x705 && + SYN_CAP_SUBMODEL_ID(info->capabilities) != 0x47) { + return -ENXIO; } /* * Unless capExtended is set the rest of the flags should be ignored */ - if (!SYN_CAP_EXTENDED(priv->capabilities)) - priv->capabilities = 0; + if (!SYN_CAP_EXTENDED(info->capabilities)) + info->capabilities = 0; - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 1) { + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB, + &info->ext_cap); + if (error) { psmouse_warn(psmouse, "device claims to have extended capabilities, but I'm not able to read them.\n"); } else { - priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - /* * if nExtBtn is greater than 8 it should be considered * invalid and treated as 0 */ - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) - priv->ext_cap &= 0xff0fff; + if (SYN_CAP_MULTI_BUTTON_NO(info->ext_cap) > 8) + info->ext_cap &= ~SYN_CAP_MB_MASK; } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 4) { + error = synaptics_query_int(psmouse, SYN_QUE_EXT_CAPAB_0C, + &info->ext_cap_0c); + if (error) psmouse_warn(psmouse, "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - } else { - priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - } } return 0; } /* - * Identify Touchpad - * See also the SYN_ID_* macros - */ -static int synaptics_identify(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char id[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) - return -1; - priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; - if (SYN_ID_IS_SYNAPTICS(priv->identity)) - return 0; - return -1; -} - -/* * Read touchpad resolution and maximum reported coordinates * Resolution is left zero if touchpad does not support the query */ - -static int synaptics_resolution(struct psmouse *psmouse) +static int synaptics_resolution(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; - unsigned char resp[3]; + u8 resp[3]; + int error; - if (SYN_ID_MAJOR(priv->identity) < 4) + if (SYN_ID_MAJOR(info->identity) < 4) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) { + error = synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp); + if (!error) { if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) { - priv->x_res = resp[0]; /* x resolution in units/mm */ - priv->y_res = resp[2]; /* y resolution in units/mm */ + info->x_res = resp[0]; /* x resolution in units/mm */ + info->y_res = resp[2]; /* y resolution in units/mm */ } } - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && - SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { + if (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 5 && + SYN_CAP_MAX_DIMENSIONS(info->ext_cap_0c)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MAX_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have max coordinates query, but I'm not able to read it.\n"); } else { - priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried max coordinates: x [..%d], y [..%d]\n", - priv->x_max, priv->y_max); + info->x_max, info->y_max); } } - if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) && - (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 || + if (SYN_CAP_MIN_DIMENSIONS(info->ext_cap_0c) && + (SYN_EXT_CAP_REQUESTS(info->capabilities) >= 7 || /* * Firmware v8.1 does not report proper number of extended * capabilities, but has been proven to report correct min * coordinates. */ - SYN_ID_FULL(priv->identity) == 0x801)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { + SYN_ID_FULL(info->identity) == 0x801)) { + error = synaptics_send_cmd(psmouse, + SYN_QUE_EXT_MIN_COORDS, resp); + if (error) { psmouse_warn(psmouse, "device claims to have min coordinates query, but I'm not able to read it.\n"); } else { - priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + info->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); + info->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); psmouse_info(psmouse, "queried min coordinates: x [%d..], y [%d..]\n", - priv->x_min, priv->y_min); + info->x_min, info->y_min); } } return 0; } +static int synaptics_query_hardware(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + int error; + + error = synaptics_identify(psmouse, info); + if (error) + return error; + + error = synaptics_model_id(psmouse, info); + if (error) + return error; + + error = synaptics_firmware_id(psmouse, info); + if (error) + return error; + + error = synaptics_query_modes(psmouse, info); + if (error) + return error; + + error = synaptics_capability(psmouse, info); + if (error) + return error; + + error = synaptics_resolution(psmouse, info); + if (error) + return error; + + return 0; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS + +static bool cr48_profile_sensor; + +#define ANY_BOARD_ID 0 +struct min_max_quirk { + const char * const *pnp_ids; + struct { + u32 min, max; + } board_id; + u32 x_min, x_max, y_min, y_max; +}; + +static const struct min_max_quirk min_max_pnpid_table[] = { + { + (const char * const []){"LEN0033", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5052, 2258, 4832 + }, + { + (const char * const []){"LEN0042", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1232, 5710, 1156, 4696 + }, + { + (const char * const []){"LEN0034", "LEN0036", "LEN0037", + "LEN0039", "LEN2002", "LEN2004", + NULL}, + {ANY_BOARD_ID, 2961}, + 1024, 5112, 2024, 4832 + }, + { + (const char * const []){"LEN2000", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5113, 2021, 4832 + }, + { + (const char * const []){"LEN2001", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1024, 5022, 2508, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {2691, 2691}, + 1024, 5045, 2457, 4832 + }, + { + (const char * const []){"LEN2006", NULL}, + {ANY_BOARD_ID, ANY_BOARD_ID}, + 1264, 5675, 1171, 4688 + }, + { } +}; + +/* This list has been kindly provided by Synaptics. */ +static const char * const forcepad_pnp_ids[] = { + "SYN300D", + "SYN3014", + NULL +}; + +/***************************************************************************** + * Synaptics communications functions + ****************************************************************************/ + +/* + * Synaptics touchpads report the y coordinate from bottom to top, which is + * opposite from what userspace expects. + * This function is used to invert y before reporting. + */ +static int synaptics_invert_y(int y) +{ + return YMAX_NOMINAL + YMIN_NOMINAL - y; +} + /* * Apply quirk(s) if the hardware matches */ - -static void synaptics_apply_quirks(struct psmouse *psmouse) +static void synaptics_apply_quirks(struct psmouse *psmouse, + struct synaptics_device_info *info) { - struct synaptics_data *priv = psmouse->private; int i; for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { @@ -454,62 +515,45 @@ static void synaptics_apply_quirks(struct psmouse *psmouse) continue; if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID && - priv->board_id < min_max_pnpid_table[i].board_id.min) + info->board_id < min_max_pnpid_table[i].board_id.min) continue; if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID && - priv->board_id > min_max_pnpid_table[i].board_id.max) + info->board_id > min_max_pnpid_table[i].board_id.max) continue; - priv->x_min = min_max_pnpid_table[i].x_min; - priv->x_max = min_max_pnpid_table[i].x_max; - priv->y_min = min_max_pnpid_table[i].y_min; - priv->y_max = min_max_pnpid_table[i].y_max; + info->x_min = min_max_pnpid_table[i].x_min; + info->x_max = min_max_pnpid_table[i].x_max; + info->y_min = min_max_pnpid_table[i].y_min; + info->y_max = min_max_pnpid_table[i].y_max; psmouse_info(psmouse, "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n", - priv->x_min, priv->x_max, - priv->y_min, priv->y_max); + info->x_min, info->x_max, + info->y_min, info->y_max); break; } } -static int synaptics_query_hardware(struct psmouse *psmouse) -{ - if (synaptics_identify(psmouse)) - return -1; - if (synaptics_model_id(psmouse)) - return -1; - if (synaptics_firmware_id(psmouse)) - return -1; - if (synaptics_query_modes(psmouse)) - return -1; - if (synaptics_capability(psmouse)) - return -1; - if (synaptics_resolution(psmouse)) - return -1; - - synaptics_apply_quirks(psmouse); - - return 0; -} - static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) { - static unsigned char param = 0xc8; + static u8 param = 0xc8; struct synaptics_data *priv = psmouse->private; + int error; - if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) + if (!(SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c))) return 0; - if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) - return -1; + error = psmouse_sliced_command(psmouse, SYN_QUE_MODEL); + if (error) + return error; - if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE)) - return -1; + error = ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE); + if (error) + return error; /* Advanced gesture mode also sends multi finger data */ - priv->capabilities |= BIT(1); + priv->info.capabilities |= BIT(1); return 0; } @@ -517,6 +561,7 @@ static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) static int synaptics_set_mode(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; + int error; priv->mode = 0; if (priv->absolute_mode) @@ -525,16 +570,21 @@ static int synaptics_set_mode(struct psmouse *psmouse) priv->mode |= SYN_BIT_DISABLE_GESTURE; if (psmouse->rate >= 80) priv->mode |= SYN_BIT_HIGH_RATE; - if (SYN_CAP_EXTENDED(priv->capabilities)) + if (SYN_CAP_EXTENDED(priv->info.capabilities)) priv->mode |= SYN_BIT_W_MODE; - if (synaptics_mode_cmd(psmouse, priv->mode)) - return -1; + error = synaptics_mode_cmd(psmouse, priv->mode); + if (error) + return error; - if (priv->absolute_mode && - synaptics_set_advanced_gesture_mode(psmouse)) { - psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); - return -1; + if (priv->absolute_mode) { + error = synaptics_set_advanced_gesture_mode(psmouse); + if (error) { + psmouse_err(psmouse, + "Advanced gesture mode init failed: %d\n", + error); + return error; + } } return 0; @@ -558,15 +608,20 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *serio, unsigned char c) +static int synaptics_pt_write(struct serio *serio, u8 c) { struct psmouse *parent = serio_get_drvdata(serio->parent); - char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ + int error; + + error = psmouse_sliced_command(parent, c); + if (error) + return error; + + error = ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE); + if (error) + return error; - if (psmouse_sliced_command(parent, c)) - return -1; - if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) - return -1; return 0; } @@ -592,13 +647,12 @@ static void synaptics_pt_stop(struct serio *serio) serio_continue_rx(parent->ps2dev.serio); } -static int synaptics_is_pt_packet(unsigned char *buf) +static int synaptics_is_pt_packet(u8 *buf) { return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; } -static void synaptics_pass_pt_packet(struct serio *ptport, - unsigned char *packet) +static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) { struct psmouse *child = serio_get_drvdata(ptport); @@ -661,7 +715,7 @@ static void synaptics_pt_create(struct psmouse *psmouse) * Functions to interpret the absolute mode packets ****************************************************************************/ -static void synaptics_parse_agm(const unsigned char buf[], +static void synaptics_parse_agm(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { @@ -688,31 +742,31 @@ static void synaptics_parse_agm(const unsigned char buf[], } } -static void synaptics_parse_ext_buttons(const unsigned char buf[], +static void synaptics_parse_ext_buttons(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { unsigned int ext_bits = - (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; unsigned int ext_mask = GENMASK(ext_bits - 1, 0); hw->ext_buttons = buf[4] & ext_mask; hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; } -static int synaptics_parse_hw_state(const unsigned char buf[], +static int synaptics_parse_hw_state(const u8 buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw) { memset(hw, 0, sizeof(struct synaptics_hw_state)); - if (SYN_MODEL_NEWABS(priv->model_id)) { + if (SYN_MODEL_NEWABS(priv->info.model_id)) { hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); - if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && + if ((SYN_CAP_ADV_GESTURE(priv->info.ext_cap_0c) || + SYN_CAP_IMAGE_SENSOR(priv->info.ext_cap_0c)) && hw->w == 2) { synaptics_parse_agm(buf, priv, hw); return 1; @@ -765,7 +819,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->left = priv->report_press; - } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + } else if (SYN_CAP_CLICKPAD(priv->info.ext_cap_0c)) { /* * Clickpad's button is transmitted as middle button, * however, since it is primary button, we will report @@ -773,18 +827,18 @@ static int synaptics_parse_hw_state(const unsigned char buf[], */ hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + } else if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) - hw->scroll = (signed char)(buf[1]); + hw->scroll = (s8)buf[1]; } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && + if (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) > 0 && ((buf[0] ^ buf[3]) & 0x02)) { synaptics_parse_ext_buttons(buf, priv, hw); } @@ -853,24 +907,24 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; - int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; + int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap) + 1) >> 1; int i; - if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) + if (!SYN_CAP_MULTI_BUTTON_NO(priv->info.ext_cap)) return; /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */ - if ((SYN_ID_FULL(priv->identity) == 0x801 || - SYN_ID_FULL(priv->identity) == 0x802) && + if ((SYN_ID_FULL(priv->info.identity) == 0x801 || + SYN_ID_FULL(priv->info.identity) == 0x802) && !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02)) return; - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) { + if (!SYN_CAP_EXT_BUTTONS_STICK(priv->info.ext_cap_10)) { for (i = 0; i < ext_bits; i++) { input_report_key(dev, BTN_0 + 2 * i, - hw->ext_buttons & (1 << i)); + hw->ext_buttons & BIT(i)); input_report_key(dev, BTN_1 + 2 * i, - hw->ext_buttons & (1 << (i + ext_bits))); + hw->ext_buttons & BIT(i + ext_bits)); } return; } @@ -884,9 +938,9 @@ static void synaptics_report_ext_buttons(struct psmouse *psmouse, u8 pt_buttons; /* The trackstick expects at most 3 buttons */ - pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) | - SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | - SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; + pt_buttons = SYN_EXT_BUTTON_STICK_L(hw->ext_buttons) | + SYN_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | + SYN_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; serio_interrupt(priv->pt_port, PSMOUSE_OOB_EXTRA_BTNS, SERIO_OOB_DATA); @@ -903,10 +957,10 @@ static void synaptics_report_buttons(struct psmouse *psmouse, input_report_key(dev, BTN_LEFT, hw->left); input_report_key(dev, BTN_RIGHT, hw->right); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(priv->info.capabilities)) input_report_key(dev, BTN_MIDDLE, hw->middle); - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(priv->info.capabilities)) { input_report_key(dev, BTN_FORWARD, hw->up); input_report_key(dev, BTN_BACK, hw->down); } @@ -931,7 +985,7 @@ static void synaptics_report_mt_data(struct psmouse *psmouse, pos[i].y = synaptics_invert_y(hw[i]->y); } - input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); + input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->info.x_res); for (i = 0; i < nsemi; i++) { input_mt_slot(dev, slot[i]); @@ -985,6 +1039,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; struct synaptics_data *priv = psmouse->private; + struct synaptics_device_info *info = &priv->info; struct synaptics_hw_state hw; int num_fingers; int finger_width; @@ -992,7 +1047,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) return; - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { synaptics_image_sensor_process(psmouse, &hw); return; } @@ -1020,18 +1075,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (hw.z > 0 && hw.x > 1) { num_fingers = 1; finger_width = 5; - if (SYN_CAP_EXTENDED(priv->capabilities)) { + if (SYN_CAP_EXTENDED(info->capabilities)) { switch (hw.w) { case 0 ... 1: - if (SYN_CAP_MULTIFINGER(priv->capabilities)) + if (SYN_CAP_MULTIFINGER(info->capabilities)) num_fingers = hw.w + 2; break; case 2: - if (SYN_MODEL_PEN(priv->model_id)) + if (SYN_MODEL_PEN(info->model_id)) ; /* Nothing, treat a pen as a single finger */ break; case 4 ... 15: - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) finger_width = hw.w; break; } @@ -1046,7 +1101,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) return; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) + if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) synaptics_report_semi_mt_data(dev, &hw, &priv->agm, num_fingers); @@ -1063,11 +1118,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) } input_report_abs(dev, ABS_PRESSURE, hw.z); - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } @@ -1077,18 +1132,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_sync(dev); } -static int synaptics_validate_byte(struct psmouse *psmouse, - int idx, unsigned char pkt_type) +static bool synaptics_validate_byte(struct psmouse *psmouse, + int idx, enum synaptics_pkt_type pkt_type) { - static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; - static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - const char *packet = psmouse->packet; + static const u8 newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; + static const u8 newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; + static const u8 oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; + static const u8 oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; + const u8 *packet = psmouse->packet; if (idx < 0 || idx > 4) - return 0; + return false; switch (pkt_type) { @@ -1104,19 +1159,21 @@ static int synaptics_validate_byte(struct psmouse *psmouse, default: psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); - return 0; + return false; } } -static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) +static enum synaptics_pkt_type +synaptics_detect_pkt_type(struct psmouse *psmouse) { int i; - for (i = 0; i < 5; i++) + for (i = 0; i < 5; i++) { if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { psmouse_info(psmouse, "using relaxed packet validation\n"); return SYN_NEWABS_RELAXED; } + } return SYN_NEWABS_STRICT; } @@ -1129,7 +1186,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (SYN_CAP_PASS_THROUGH(priv->capabilities) && + if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) && synaptics_is_pt_packet(psmouse->packet)) { if (priv->pt_port) synaptics_pass_pt_packet(priv->pt_port, @@ -1148,26 +1205,27 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) * Driver initialization/cleanup functions ****************************************************************************/ static void set_abs_position_params(struct input_dev *dev, - struct synaptics_data *priv, int x_code, - int y_code) + struct synaptics_device_info *info, + int x_code, int y_code) { - int x_min = priv->x_min ?: XMIN_NOMINAL; - int x_max = priv->x_max ?: XMAX_NOMINAL; - int y_min = priv->y_min ?: YMIN_NOMINAL; - int y_max = priv->y_max ?: YMAX_NOMINAL; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? + int x_min = info->x_min ?: XMIN_NOMINAL; + int x_max = info->x_max ?: XMAX_NOMINAL; + int y_min = info->y_min ?: YMIN_NOMINAL; + int y_max = info->y_max ?: YMAX_NOMINAL; + int fuzz = SYN_CAP_REDUCED_FILTERING(info->ext_cap_0c) ? SYN_REDUCED_FILTER_FUZZ : 0; input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); - input_abs_set_res(dev, x_code, priv->x_res); - input_abs_set_res(dev, y_code, priv->y_res); + input_abs_set_res(dev, x_code, info->x_res); + input_abs_set_res(dev, y_code, info->y_res); } static void set_input_params(struct psmouse *psmouse, struct synaptics_data *priv) { struct input_dev *dev = psmouse->dev; + struct synaptics_device_info *info = &priv->info; int i; /* Things that apply to both modes */ @@ -1176,7 +1234,7 @@ static void set_input_params(struct psmouse *psmouse, __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) + if (SYN_CAP_MIDDLE_BUTTON(info->capabilities)) __set_bit(BTN_MIDDLE, dev->keybit); if (!priv->absolute_mode) { @@ -1189,15 +1247,15 @@ static void set_input_params(struct psmouse *psmouse, /* Absolute mode */ __set_bit(EV_ABS, dev->evbit); - set_abs_position_params(dev, priv, ABS_X, ABS_Y); + set_abs_position_params(dev, &priv->info, ABS_X, ABS_Y); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); if (cr48_profile_sensor) input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + if (SYN_CAP_IMAGE_SENSOR(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* Image sensors can report per-contact pressure */ input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); @@ -1205,9 +1263,9 @@ static void set_input_params(struct psmouse *psmouse, /* Image sensors can signal 4 and 5 finger clicks */ __set_bit(BTN_TOOL_QUADTAP, dev->keybit); __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); - } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); + } else if (SYN_CAP_ADV_GESTURE(info->ext_cap_0c)) { + set_abs_position_params(dev, info, + ABS_MT_POSITION_X, ABS_MT_POSITION_Y); /* * Profile sensor in CR-48 tracks contacts reasonably well, * other non-image sensors with AGM use semi-mt. @@ -1218,35 +1276,35 @@ static void set_input_params(struct psmouse *psmouse, INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); } - if (SYN_CAP_PALMDETECT(priv->capabilities)) + if (SYN_CAP_PALMDETECT(info->capabilities)) input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); __set_bit(BTN_TOUCH, dev->keybit); __set_bit(BTN_TOOL_FINGER, dev->keybit); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(info->capabilities)) { __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } - if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || - SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + if (SYN_CAP_FOUR_BUTTON(info->capabilities) || + SYN_CAP_MIDDLE_BUTTON(info->capabilities)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); } - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) + if (!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) + for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(info->ext_cap); i++) __set_bit(BTN_0 + i, dev->keybit); __clear_bit(EV_REL, dev->evbit); __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + if (SYN_CAP_CLICKPAD(info->ext_cap_0c)) { __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && - !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10)) __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); /* Clickpads report only left button */ __clear_bit(BTN_RIGHT, dev->keybit); @@ -1300,7 +1358,14 @@ static void synaptics_disconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) + /* + * We might have left a breadcrumb when trying to + * set up SMbus companion. + */ + psmouse_smbus_cleanup(psmouse); + + if (!priv->absolute_mode && + SYN_ID_DISGEST_SUPPORTED(priv->info.identity)) device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); @@ -1312,8 +1377,8 @@ static void synaptics_disconnect(struct psmouse *psmouse) static int synaptics_reconnect(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - struct synaptics_data old_priv = *priv; - unsigned char param[2]; + struct synaptics_device_info info; + u8 param[2]; int retry = 0; int error; @@ -1334,32 +1399,34 @@ static int synaptics_reconnect(struct psmouse *psmouse) } while (error && ++retry < 3); if (error) - return -1; + return error; if (retry > 1) psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - if (synaptics_query_hardware(psmouse)) { + error = synaptics_query_hardware(psmouse, &info); + if (error) { psmouse_err(psmouse, "Unable to query device.\n"); - return -1; + return error; } - if (synaptics_set_mode(psmouse)) { + error = synaptics_set_mode(psmouse); + if (error) { psmouse_err(psmouse, "Unable to initialize device.\n"); - return -1; + return error; } - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) { + if (info.identity != priv->info.identity || + info.model_id != priv->info.model_id || + info.capabilities != priv->info.capabilities || + info.ext_cap != priv->info.ext_cap) { psmouse_err(psmouse, - "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); - return -1; + "hardware appears to be different: id(%u-%u), model(%u-%u), caps(%x-%x), ext(%x-%x).\n", + priv->info.identity, info.identity, + priv->info.model_id, info.model_id, + priv->info.capabilities, info.capabilities, + priv->info.ext_cap, info.ext_cap); + return -ENXIO; } return 0; @@ -1439,36 +1506,22 @@ void __init synaptics_module_init(void) cr48_profile_sensor = dmi_check_system(cr48_dmi_table); } -static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +static int synaptics_init_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool absolute_mode) { struct synaptics_data *priv; - int err = -1; + int err; - /* - * The OLPC XO has issues with Synaptics' absolute mode; the constant - * packet spew overloads the EC such that key presses on the keyboard - * are missed. Given that, don't even attempt to use Absolute mode. - * Relative mode seems to work just fine. - */ - if (absolute_mode && broken_olpc_ec) { - psmouse_info(psmouse, - "OLPC XO detected, not enabling Synaptics protocol.\n"); - return -ENODEV; - } + synaptics_apply_quirks(psmouse, info); psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); if (!priv) return -ENOMEM; - psmouse_reset(psmouse); - - if (synaptics_query_hardware(psmouse)) { - psmouse_err(psmouse, "Unable to query device.\n"); - goto init_fail; - } - + priv->info = *info; priv->absolute_mode = absolute_mode; - if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) + if (SYN_ID_DISGEST_SUPPORTED(info->identity)) priv->disable_gesture = true; /* @@ -1477,20 +1530,22 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) */ priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids); - if (synaptics_set_mode(psmouse)) { + err = synaptics_set_mode(psmouse); + if (err) { psmouse_err(psmouse, "Unable to initialize device.\n"); goto init_fail; } - priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; + priv->pkt_type = SYN_MODEL_NEWABS(info->model_id) ? + SYN_NEWABS : SYN_OLDABS; psmouse_info(psmouse, - "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n", - SYN_ID_MODEL(priv->identity), - SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, - priv->capabilities, priv->ext_cap, priv->ext_cap_0c, - priv->ext_cap_10, priv->board_id, priv->firmware_id); + "Touchpad model: %lu, fw: %lu.%lu, id: %#x, caps: %#x/%#x/%#x/%#x, board id: %u, fw id: %u\n", + SYN_ID_MODEL(info->identity), + SYN_ID_MAJOR(info->identity), SYN_ID_MINOR(info->identity), + info->model_id, + info->capabilities, info->ext_cap, info->ext_cap_0c, + info->ext_cap_10, info->board_id, info->firmware_id); set_input_params(psmouse, priv); @@ -1501,8 +1556,8 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) * Hardware info bits seem to be good candidates as they * are documented to be for Synaptics corp. internal use. */ - psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | - (priv->model_id & 0x000000ff); + psmouse->model = ((info->model_id & 0x00ff0000) >> 8) | + (info->model_id & 0x000000ff); if (absolute_mode) { psmouse->protocol_handler = synaptics_process_byte; @@ -1520,7 +1575,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) /* Synaptics can usually stay in sync without extra help */ psmouse->resync_time = 0; - if (SYN_CAP_PASS_THROUGH(priv->capabilities)) + if (SYN_CAP_PASS_THROUGH(info->capabilities)) synaptics_pt_create(psmouse); /* @@ -1535,7 +1590,7 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) psmouse->rate = 40; } - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) { + if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(info->identity)) { err = device_create_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_disable_gesture.dattr); if (err) { @@ -1553,7 +1608,23 @@ static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) return err; } -int synaptics_init(struct psmouse *psmouse) +static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + return synaptics_init_ps2(psmouse, &info, absolute_mode); +} + +int synaptics_init_absolute(struct psmouse *psmouse) { return __synaptics_init(psmouse, true); } @@ -1563,15 +1634,204 @@ int synaptics_init_relative(struct psmouse *psmouse) return __synaptics_init(psmouse, false); } +static int synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) +{ + bool absolute_mode = true; + int error; + + /* + * The OLPC XO has issues with Synaptics' absolute mode; the constant + * packet spew overloads the EC such that key presses on the keyboard + * are missed. Given that, don't even attempt to use Absolute mode. + * Relative mode seems to work just fine. + */ + if (broken_olpc_ec) { + psmouse_info(psmouse, + "OLPC XO detected, forcing relative protocol.\n"); + absolute_mode = false; + } + + error = synaptics_init_ps2(psmouse, info, absolute_mode); + if (error) + return error; + + return absolute_mode ? PSMOUSE_SYNAPTICS : PSMOUSE_SYNAPTICS_RELATIVE; +} + #else /* CONFIG_MOUSE_PS2_SYNAPTICS */ void __init synaptics_module_init(void) { } -int synaptics_init(struct psmouse *psmouse) +static int __maybe_unused +synaptics_setup_ps2(struct psmouse *psmouse, + struct synaptics_device_info *info) { return -ENOSYS; } #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS + +/* + * The newest Synaptics device can use a secondary bus (called InterTouch) which + * provides a better bandwidth and allow a better control of the touchpads. + * This is used to decide if we need to use this bus or not. + */ +enum { + SYNAPTICS_INTERTOUCH_NOT_SET = -1, + SYNAPTICS_INTERTOUCH_OFF, + SYNAPTICS_INTERTOUCH_ON, +}; + +static int synaptics_intertouch = SYNAPTICS_INTERTOUCH_NOT_SET; +module_param_named(synaptics_intertouch, synaptics_intertouch, int, 0644); +MODULE_PARM_DESC(synaptics_intertouch, "Use a secondary bus for the Synaptics device."); + +static int synaptics_create_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + bool topbuttonpad = + psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10); + const struct rmi_device_platform_data pdata = { + .sensor_pdata = { + .sensor_type = rmi_sensor_touchpad, + .axis_align.flip_y = true, + /* to prevent cursors jumps: */ + .kernel_tracking = true, + .topbuttonpad = topbuttonpad, + }, + .f30_data = { + .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c), + .trackstick_buttons = + !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10), + }, + }; + const struct i2c_board_info intertouch_board = { + I2C_BOARD_INFO("rmi4_smbus", 0x2c), + .flags = I2C_CLIENT_HOST_NOTIFY, + }; + + return psmouse_smbus_init(psmouse, &intertouch_board, + &pdata, sizeof(pdata), + leave_breadcrumbs); +} + +/** + * synaptics_setup_intertouch - called once the PS/2 devices are enumerated + * and decides to instantiate a SMBus InterTouch device. + */ +static int synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + int error; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_OFF) + return -ENXIO; + + if (synaptics_intertouch == SYNAPTICS_INTERTOUCH_NOT_SET) { + if (!psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && + !psmouse_matches_pnp_id(psmouse, smbus_pnp_ids)) + return -ENXIO; + } + + psmouse_info(psmouse, "Trying to set up SMBus access\n"); + + error = synaptics_create_intertouch(psmouse, info, leave_breadcrumbs); + if (error) { + if (error == -EAGAIN) + psmouse_info(psmouse, "SMbus companion is not ready yet\n"); + else + psmouse_err(psmouse, "unable to create intertouch device\n"); + + return error; + } + + return 0; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (!SYN_CAP_INTERTOUCH(info.ext_cap_0c)) + return -ENXIO; + + return synaptics_create_intertouch(psmouse, &info, false); +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +static int __maybe_unused +synaptics_setup_intertouch(struct psmouse *psmouse, + struct synaptics_device_info *info, + bool leave_breadcrumbs) +{ + return -ENOSYS; +} + +int synaptics_init_smbus(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +#if defined(CONFIG_MOUSE_PS2_SYNAPTICS) || \ + defined(CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS) + +int synaptics_init(struct psmouse *psmouse) +{ + struct synaptics_device_info info; + int error; + int retval; + + psmouse_reset(psmouse); + + error = synaptics_query_hardware(psmouse, &info); + if (error) { + psmouse_err(psmouse, "Unable to query device: %d\n", error); + return error; + } + + if (SYN_CAP_INTERTOUCH(info.ext_cap_0c)) { + error = synaptics_setup_intertouch(psmouse, &info, true); + if (!error) + return PSMOUSE_SYNAPTICS_SMBUS; + } + + retval = synaptics_setup_ps2(psmouse, &info); + if (retval < 0) { + /* + * Not using any flavor of Synaptics support, so clean up + * SMbus breadcrumbs, if any. + */ + psmouse_smbus_cleanup(psmouse); + } + + return retval; +} + +#else /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ + +int synaptics_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} + +#endif /* CONFIG_MOUSE_PS2_SYNAPTICS || CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS */ diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 116ae2546ace..fc00e005c611 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -25,36 +25,37 @@ #define SYN_QUE_MEXT_CAPAB_10 0x10 /* synatics modes */ -#define SYN_BIT_ABSOLUTE_MODE (1 << 7) -#define SYN_BIT_HIGH_RATE (1 << 6) -#define SYN_BIT_SLEEP_MODE (1 << 3) -#define SYN_BIT_DISABLE_GESTURE (1 << 2) -#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1) -#define SYN_BIT_W_MODE (1 << 0) +#define SYN_BIT_ABSOLUTE_MODE BIT(7) +#define SYN_BIT_HIGH_RATE BIT(6) +#define SYN_BIT_SLEEP_MODE BIT(3) +#define SYN_BIT_DISABLE_GESTURE BIT(2) +#define SYN_BIT_FOUR_BYTE_CLIENT BIT(1) +#define SYN_BIT_W_MODE BIT(0) /* synaptics model ID bits */ -#define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) -#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) -#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) -#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) -#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) -#define SYN_MODEL_PEN(m) ((m) & (1 << 6)) -#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) -#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) +#define SYN_MODEL_ROT180(m) ((m) & BIT(23)) +#define SYN_MODEL_PORTRAIT(m) ((m) & BIT(22)) +#define SYN_MODEL_SENSOR(m) (((m) & GENMASK(21, 16)) >> 16) +#define SYN_MODEL_HARDWARE(m) (((m) & GENMASK(15, 9)) >> 9) +#define SYN_MODEL_NEWABS(m) ((m) & BIT(7)) +#define SYN_MODEL_PEN(m) ((m) & BIT(6)) +#define SYN_MODEL_SIMPLIC(m) ((m) & BIT(5)) +#define SYN_MODEL_GEOMETRY(m) ((m) & GENMASK(3, 0)) /* synaptics capability bits */ -#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) -#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) -#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) -#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) -#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) -#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) -#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) -#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) -#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) -#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) -#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) +#define SYN_CAP_EXTENDED(c) ((c) & BIT(23)) +#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & BIT(18)) +#define SYN_CAP_PASS_THROUGH(c) ((c) & BIT(7)) +#define SYN_CAP_SLEEP(c) ((c) & BIT(4)) +#define SYN_CAP_FOUR_BUTTON(c) ((c) & BIT(3)) +#define SYN_CAP_MULTIFINGER(c) ((c) & BIT(1)) +#define SYN_CAP_PALMDETECT(c) ((c) & BIT(0)) +#define SYN_CAP_SUBMODEL_ID(c) (((c) & GENMASK(15, 8)) >> 8) +#define SYN_EXT_CAP_REQUESTS(c) (((c) & GENMASK(22, 20)) >> 20) +#define SYN_CAP_MB_MASK GENMASK(15, 12) +#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & SYN_CAP_MB_MASK) >> 12) +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & GENMASK(23, 16)) >> 16) +#define SYN_MEXT_CAP_BIT(m) ((m) & BIT(1)) /* * The following describes response for the 0x0c query. @@ -83,13 +84,14 @@ * hinged at the top. * 2 0x20 report min query 0x0f gives min coord reported */ -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ -#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ -#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) -#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) -#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) -#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) -#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & BIT(20)) /* 1-button ClickPad */ +#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & BIT(8)) /* 2-button ClickPad */ +#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & BIT(17)) +#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & BIT(13)) +#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & BIT(19)) +#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & BIT(10)) +#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & BIT(11)) +#define SYN_CAP_INTERTOUCH(ex0c) ((ex0c) & BIT(14)) /* * The following descibes response for the 0x10 query. @@ -108,42 +110,44 @@ * 3 0xff SecurePad height the height of the SecurePad fingerprint * reader. */ -#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) -#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) +#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & BIT(16)) +#define SYN_CAP_SECUREPAD(ex10) ((ex10) & BIT(17)) -#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01)) -#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02)) -#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04)) +#define SYN_EXT_BUTTON_STICK_L(eb) (((eb) & BIT(0)) >> 0) +#define SYN_EXT_BUTTON_STICK_M(eb) (((eb) & BIT(1)) >> 1) +#define SYN_EXT_BUTTON_STICK_R(eb) (((eb) & BIT(2)) >> 2) /* synaptics modes query bits */ -#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -#define SYN_MODE_RATE(m) ((m) & (1 << 6)) -#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) -#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) -#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) -#define SYN_MODE_WMODE(m) ((m) & (1 << 0)) +#define SYN_MODE_ABSOLUTE(m) ((m) & BIT(7)) +#define SYN_MODE_RATE(m) ((m) & BIT(6)) +#define SYN_MODE_BAUD_SLEEP(m) ((m) & BIT(3)) +#define SYN_MODE_DISABLE_GESTURE(m) ((m) & BIT(2)) +#define SYN_MODE_PACKSIZE(m) ((m) & BIT(1)) +#define SYN_MODE_WMODE(m) ((m) & BIT(0)) /* synaptics identify query bits */ -#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) -#define SYN_ID_MAJOR(i) ((i) & 0x0f) -#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) +#define SYN_ID_MODEL(i) (((i) & GENMASK(7, 4)) >> 4) +#define SYN_ID_MAJOR(i) (((i) & GENMASK(3, 0)) >> 0) +#define SYN_ID_MINOR(i) (((i) & GENMASK(23, 16)) >> 16) #define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) -#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) +#define SYN_ID_IS_SYNAPTICS(i) (((i) & GENMASK(15, 8)) == 0x004700U) #define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4) /* synaptics special commands */ #define SYN_PS_SET_MODE2 0x14 #define SYN_PS_CLIENT_CMD 0x28 -/* synaptics packet types */ -#define SYN_NEWABS 0 -#define SYN_NEWABS_STRICT 1 -#define SYN_NEWABS_RELAXED 2 -#define SYN_OLDABS 3 - /* amount to fuzz position data when touchpad reports reduced filtering */ #define SYN_REDUCED_FILTER_FUZZ 8 +/* synaptics packet types */ +enum synaptics_pkt_type { + SYN_NEWABS, + SYN_NEWABS_STRICT, + SYN_NEWABS_RELAXED, + SYN_OLDABS, +}; + /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -157,26 +161,30 @@ struct synaptics_hw_state { unsigned int middle:1; unsigned int up:1; unsigned int down:1; - unsigned char ext_buttons; - signed char scroll; + u8 ext_buttons; + s8 scroll; +}; + +/* Data read from the touchpad */ +struct synaptics_device_info { + u32 model_id; /* Model-ID */ + u32 firmware_id; /* Firmware-ID */ + u32 board_id; /* Board-ID */ + u32 capabilities; /* Capabilities */ + u32 ext_cap; /* Extended Capabilities */ + u32 ext_cap_0c; /* Ext Caps from 0x0c query */ + u32 ext_cap_10; /* Ext Caps from 0x10 query */ + u32 identity; /* Identification */ + u32 x_res, y_res; /* X/Y resolution in units/mm */ + u32 x_max, y_max; /* Max coordinates (from FW) */ + u32 x_min, y_min; /* Min coordinates (from FW) */ }; struct synaptics_data { - /* Data read from the touchpad */ - unsigned long int model_id; /* Model-ID */ - unsigned long int firmware_id; /* Firmware-ID */ - unsigned long int board_id; /* Board-ID */ - unsigned long int capabilities; /* Capabilities */ - unsigned long int ext_cap; /* Extended Capabilities */ - unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ - unsigned long int ext_cap_10; /* Ext Caps from 0x10 query */ - unsigned long int identity; /* Identification */ - unsigned int x_res, y_res; /* X/Y resolution in units/mm */ - unsigned int x_max, y_max; /* Max coordinates (from FW) */ - unsigned int x_min, y_min; /* Min coordinates (from FW) */ - - unsigned char pkt_type; /* packet type - old, new, etc */ - unsigned char mode; /* current mode byte */ + struct synaptics_device_info info; + + enum synaptics_pkt_type pkt_type; /* packet type - old, new, etc */ + u8 mode; /* current mode byte */ int scroll; bool absolute_mode; /* run in Absolute mode */ @@ -200,8 +208,10 @@ struct synaptics_data { void synaptics_module_init(void); int synaptics_detect(struct psmouse *psmouse, bool set_properties); -int synaptics_init(struct psmouse *psmouse); +int synaptics_init_absolute(struct psmouse *psmouse); int synaptics_init_relative(struct psmouse *psmouse); +int synaptics_init_smbus(struct psmouse *psmouse); +int synaptics_init(struct psmouse *psmouse); void synaptics_reset(struct psmouse *psmouse); #endif /* _SYNAPTICS_H */ diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index cb2bf203f4ca..8538318d332c 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -652,9 +652,18 @@ static const struct i2c_device_id synaptics_i2c_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); +#ifdef CONFIG_OF +static const struct of_device_id synaptics_i2c_of_match[] = { + { .compatible = "synaptics,synaptics_i2c", }, + { }, +}; +MODULE_DEVICE_TABLE(of, synaptics_i2c_of_match); +#endif + static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, + .of_match_table = of_match_ptr(synaptics_i2c_of_match), .pm = &synaptics_i2c_pm, }, diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index d64fc92858f2..4f2bb5947a4e 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -251,7 +251,7 @@ static int rmi_irq_init(struct rmi_device *rmi_dev) ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL, rmi_irq_fn, irq_flags | IRQF_ONESHOT, - dev_name(rmi_dev->xport->dev), + dev_driver_string(rmi_dev->xport->dev), rmi_dev); if (ret < 0) { dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n", @@ -1234,16 +1234,21 @@ static int rmi_driver_probe(struct device *dev) if (retval < 0) goto err_destroy_functions; - if (data->f01_container->dev.driver) + if (data->f01_container->dev.driver) { /* Driver already bound, so enable ATTN now. */ - return rmi_enable_sensor(rmi_dev); + retval = rmi_enable_sensor(rmi_dev); + if (retval) + goto err_disable_irq; + } return 0; +err_disable_irq: + rmi_disable_irq(rmi_dev, false); err_destroy_functions: rmi_free_function_list(rmi_dev); err: - return retval < 0 ? retval : 0; + return retval; } static struct rmi_driver rmi_physical_driver = { diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 07aff4356fe0..8b0db086d68a 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -113,20 +113,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) } if (rmi_register_desc_has_subpacket(item, 2)) { - sensor->axis_align.clip_x_low = buf[offset]; - sensor->axis_align.clip_x_high = sensor->max_x - - buf[offset + 1]; - sensor->axis_align.clip_y_low = buf[offset + 2]; - sensor->axis_align.clip_y_high = sensor->max_y - - buf[offset + 3]; + /* Units 1/128 sensor pitch */ + rmi_dbg(RMI_DEBUG_FN, &fn->dev, + "%s: Inactive Border xlo:%d xhi:%d ylo:%d yhi:%d\n", + __func__, + buf[offset], buf[offset + 1], + buf[offset + 2], buf[offset + 3]); + offset += 4; } - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n", - __func__, - sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high, - sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high); - if (rmi_register_desc_has_subpacket(item, 3)) { rx_receivers = buf[offset]; tx_receivers = buf[offset + 1]; diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 425fe140e9df..b8ee78e0d61f 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -105,16 +105,27 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits) { struct f34_data *f34 = dev_get_drvdata(&fn->dev); int ret; + u8 status; - if (f34->bl_version != 5) - return 0; + if (f34->bl_version == 5) { + ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, + &status); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", + __func__, status, ret); - ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); - rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", - __func__, f34->v5.status, ret); - - if (!ret && !(f34->v5.status & 0x7f)) - complete(&f34->v5.cmd_done); + if (!ret && !(status & 0x7f)) + complete(&f34->v5.cmd_done); + } else { + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.data_base_addr + + f34->v7.off.flash_status, + &status, sizeof(status)); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", + __func__, status, ret); + + if (!ret && !(status & 0x1f)) + complete(&f34->v7.cmd_done); + } return 0; } diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h index 43a91349b28d..32c4e9581c68 100644 --- a/drivers/input/rmi4/rmi_f34.h +++ b/drivers/input/rmi4/rmi_f34.h @@ -30,6 +30,7 @@ #define F34_IDLE_WAIT_MS 500 #define F34_ENABLE_WAIT_MS 300 #define F34_ERASE_WAIT_MS 5000 +#define F34_WRITE_WAIT_MS 3000 #define F34_BOOTLOADER_ID_LEN 2 @@ -47,11 +48,6 @@ #define CONFIG_ID_SIZE 32 #define PRODUCT_ID_SIZE 10 -#define ENABLE_WAIT_MS (1 * 1000) -#define WRITE_WAIT_MS (3 * 1000) - -#define MIN_SLEEP_TIME_US 50 -#define MAX_SLEEP_TIME_US 100 #define HAS_BSR BIT(5) #define HAS_CONFIG_ID BIT(3) @@ -292,6 +288,7 @@ struct f34v7_data { const void *config_data; const void *image; + struct completion cmd_done; }; struct f34_data { diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c index 56c6c39ad31e..10c0d11b72c9 100644 --- a/drivers/input/rmi4/rmi_f34v7.c +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -15,6 +15,7 @@ #include <asm/unaligned.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/jiffies.h> #include "rmi_driver.h" #include "rmi_f34.h" @@ -31,7 +32,7 @@ static int rmi_f34v7_read_flash_status(struct f34_data *f34) sizeof(status)); if (ret < 0) { rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, - "%s: Failed to read flash status\n", __func__); + "%s: Error %d reading flash status\n", __func__, ret); return ret; } @@ -60,28 +61,17 @@ static int rmi_f34v7_read_flash_status(struct f34_data *f34) static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms) { - int count = 0; - int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + unsigned long timeout; - do { - usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); - - count++; - - rmi_f34v7_read_flash_status(f34); - - if ((f34->v7.command == v7_CMD_IDLE) - && (f34->v7.flash_status == 0x00)) { - rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, - "Idle status detected\n"); - return 0; - } - } while (count < timeout_count); + timeout = msecs_to_jiffies(timeout_ms); - dev_err(&f34->fn->dev, - "%s: Timed out waiting for idle status\n", __func__); + if (!wait_for_completion_timeout(&f34->v7.cmd_done, timeout)) { + dev_warn(&f34->fn->dev, "%s: Timed out waiting for idle status\n", + __func__); + return -ETIMEDOUT; + } - return -ETIMEDOUT; + return 0; } static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34, @@ -285,9 +275,10 @@ static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd) return 0; } -static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) +static int rmi_f34v7_read_partition_table(struct f34_data *f34) { int ret; + unsigned long timeout; u8 base; __le16 length; u16 block_number = 0; @@ -320,6 +311,8 @@ static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) return ret; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG); if (ret < 0) { dev_err(&f34->fn->dev, "%s: Failed to write command\n", @@ -327,11 +320,15 @@ static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) return ret; } - ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n", - __func__); - return ret; + timeout = msecs_to_jiffies(F34_WRITE_WAIT_MS); + while (time_before(jiffies, timeout)) { + usleep_range(5000, 6000); + rmi_f34v7_read_flash_status(f34); + + if (f34->v7.command == v7_CMD_IDLE && + f34->v7.flash_status == 0x00) { + break; + } } ret = rmi_read_block(f34->fn->rmi_dev, @@ -570,7 +567,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) f34->v7.read_config_buf_size = f34->v7.partition_table_bytes; ptable = f34->v7.read_config_buf; - ret = rmi_f34v7_read_f34v7_partition_table(f34); + ret = rmi_f34v7_read_partition_table(f34); if (ret < 0) { dev_err(&f34->fn->dev, "%s: Failed to read partition table\n", __func__); @@ -666,6 +663,8 @@ static int rmi_f34v7_erase_config(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing config...\n"); + init_completion(&f34->v7.cmd_done); + switch (f34->v7.config_area) { case v7_UI_CONFIG_AREA: ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG); @@ -684,11 +683,11 @@ static int rmi_f34v7_erase_config(struct f34_data *f34) break; } - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; - return ret; + return 0; } static int rmi_f34v7_erase_guest_code(struct f34_data *f34) @@ -697,11 +696,13 @@ static int rmi_f34v7_erase_guest_code(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing guest code...\n"); + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; @@ -714,11 +715,13 @@ static int rmi_f34v7_erase_all(struct f34_data *f34) dev_info(&f34->fn->dev, "Erasing firmware...\n"); + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ERASE_WAIT_MS); if (ret < 0) return ret; @@ -743,8 +746,8 @@ static int rmi_f34v7_erase_all(struct f34_data *f34) return 0; } -static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, - u8 command) +static int rmi_f34v7_read_blocks(struct f34_data *f34, + u16 block_cnt, u8 command) { int ret; u8 base; @@ -787,17 +790,15 @@ static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, return ret; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, command); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, - "%s: Wait for idle failed (%d blks remaining)\n", - __func__, remaining); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); + if (ret < 0) return ret; - } ret = rmi_read_block(f34->fn->rmi_dev, base + f34->v7.off.payload, @@ -853,6 +854,8 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, transfer = min(remaining, max_transfer); put_unaligned_le16(transfer, &length); + init_completion(&f34->v7.cmd_done); + ret = rmi_write_block(f34->fn->rmi_dev, base + f34->v7.off.transfer_length, &length, sizeof(length)); @@ -877,13 +880,9 @@ static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, return ret; } - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); - if (ret < 0) { - dev_err(&f34->fn->dev, - "%s: Failed wait for idle (%d blks remaining)\n", - __func__, remaining); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); + if (ret < 0) return ret; - } block_ptr += (transfer * f34->v7.block_size); remaining -= transfer; @@ -945,6 +944,8 @@ static int rmi_f34v7_write_flash_config(struct f34_data *f34) return -EINVAL; } + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG); if (ret < 0) return ret; @@ -952,7 +953,7 @@ static int rmi_f34v7_write_flash_config(struct f34_data *f34) rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Erase flash config command written\n", __func__); - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_WRITE_WAIT_MS); if (ret < 0) return ret; @@ -981,7 +982,7 @@ static int rmi_f34v7_write_partition_table(struct f34_data *f34) f34->v7.read_config_buf_size = f34->v7.config_size; - ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG); + ret = rmi_f34v7_read_blocks(f34, block_count, v7_CMD_READ_CONFIG); if (ret < 0) return ret; @@ -1287,6 +1288,8 @@ static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) { int ret; + f34->fn->rmi_dev->driver->set_irq_bits(f34->fn->rmi_dev, f34->fn->irq_mask); + ret = rmi_f34v7_read_flash_status(f34); if (ret < 0) return ret; @@ -1294,19 +1297,16 @@ static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) if (f34->v7.in_bl_mode) return 0; + init_completion(&f34->v7.cmd_done); + ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG); if (ret < 0) return ret; - ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + ret = rmi_f34v7_wait_for_idle(f34, F34_ENABLE_WAIT_MS); if (ret < 0) return ret; - if (!f34->v7.in_bl_mode) { - dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__); - return -EINVAL; - } - return 0; } @@ -1314,6 +1314,8 @@ int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw) { int ret = 0; + f34->fn->rmi_dev->driver->set_irq_bits(f34->fn->rmi_dev, f34->fn->irq_mask); + f34->v7.config_area = v7_UI_CONFIG_AREA; f34->v7.image = fw->data; @@ -1376,8 +1378,13 @@ int rmi_f34v7_probe(struct f34_data *f34) memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount)); memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr)); - rmi_f34v7_read_queries(f34); - f34->v7.force_update = false; + init_completion(&f34->v7.cmd_done); + + ret = rmi_f34v7_read_queries(f34); + if (ret < 0) + return ret; + + f34->v7.force_update = true; return 0; } diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 082306d7c207..e28663ef9e5a 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -204,7 +204,7 @@ static int rmi_i2c_probe(struct i2c_client *client, struct rmi_device_platform_data *client_pdata = dev_get_platdata(&client->dev); struct rmi_i2c_xport *rmi_i2c; - int retval; + int error; rmi_i2c = devm_kzalloc(&client->dev, sizeof(struct rmi_i2c_xport), GFP_KERNEL); @@ -220,30 +220,31 @@ static int rmi_i2c_probe(struct i2c_client *client, rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", dev_name(&client->dev)); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, - "adapter does not support required functionality.\n"); + "adapter does not support required functionality\n"); return -ENODEV; } rmi_i2c->supplies[0].supply = "vdd"; rmi_i2c->supplies[1].supply = "vio"; - retval = devm_regulator_bulk_get(&client->dev, + error = devm_regulator_bulk_get(&client->dev, ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); - if (retval < 0) - return retval; + if (error < 0) + return error; - retval = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), + error = regulator_bulk_enable(ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); - if (retval < 0) - return retval; + if (error < 0) + return error; - retval = devm_add_action_or_reset(&client->dev, + error = devm_add_action_or_reset(&client->dev, rmi_i2c_regulator_bulk_disable, rmi_i2c); - if (retval) - return retval; + if (error) + return error; of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms", &rmi_i2c->startup_delay); @@ -263,26 +264,26 @@ static int rmi_i2c_probe(struct i2c_client *client, * Setting the page to zero will (a) make sure the PSR is in a * known state, and (b) make sure we can talk to the device. */ - retval = rmi_set_page(rmi_i2c, 0); - if (retval) { - dev_err(&client->dev, "Failed to set page select to 0.\n"); - return retval; + error = rmi_set_page(rmi_i2c, 0); + if (error) { + dev_err(&client->dev, "Failed to set page select to 0\n"); + return error; } - retval = rmi_register_transport_device(&rmi_i2c->xport); - if (retval) { - dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n", - client->addr); - return retval; + dev_info(&client->dev, "registering I2C-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_i2c->xport); + if (error) { + dev_err(&client->dev, "failed to register sensor: %d\n", error); + return error; } - retval = devm_add_action_or_reset(&client->dev, + + error = devm_add_action_or_reset(&client->dev, rmi_i2c_unregister_transport, rmi_i2c); - if (retval) - return retval; + if (error) + return error; - dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n", - client->addr); return 0; } diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 76752555d809..225025a0940c 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -53,6 +53,7 @@ static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb) dev_err(&client->dev, "failed to get SMBus version number!\n"); return retval; } + return retval + 1; } @@ -83,63 +84,56 @@ static int rmi_smb_get_command_code(struct rmi_transport_dev *xport, { struct rmi_smb_xport *rmi_smb = container_of(xport, struct rmi_smb_xport, xport); + struct mapping_table_entry new_map; int i; - int retval; - struct mapping_table_entry mapping_data[1]; + int retval = 0; mutex_lock(&rmi_smb->mappingtable_mutex); + for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) { - if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) { + struct mapping_table_entry *entry = &rmi_smb->mapping_table[i]; + + if (le16_to_cpu(entry->rmiaddr) == rmiaddr) { if (isread) { - if (rmi_smb->mapping_table[i].readcount - == bytecount) { - *commandcode = i; - retval = 0; + if (entry->readcount == bytecount) goto exit; - } } else { - if (rmi_smb->mapping_table[i].flags & - RMI_SMB2_MAP_FLAGS_WE) { - *commandcode = i; - retval = 0; + if (entry->flags & RMI_SMB2_MAP_FLAGS_WE) { goto exit; } } } } + i = rmi_smb->table_index; rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE; /* constructs mapping table data entry. 4 bytes each entry */ - memset(mapping_data, 0, sizeof(mapping_data)); - - mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr); - mapping_data[0].readcount = bytecount; - mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; - - retval = smb_block_write(xport, i + 0x80, mapping_data, - sizeof(mapping_data)); + memset(&new_map, 0, sizeof(new_map)); + new_map.rmiaddr = cpu_to_le16(rmiaddr); + new_map.readcount = bytecount; + new_map.flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; + retval = smb_block_write(xport, i + 0x80, &new_map, sizeof(new_map)); if (retval < 0) { /* * if not written to device mapping table * clear the driver mapping table records */ - rmi_smb->mapping_table[i].rmiaddr = 0x0000; - rmi_smb->mapping_table[i].readcount = 0; - rmi_smb->mapping_table[i].flags = 0; - goto exit; + memset(&new_map, 0, sizeof(new_map)); } + /* save to the driver level mapping table */ - rmi_smb->mapping_table[i].rmiaddr = rmiaddr; - rmi_smb->mapping_table[i].readcount = bytecount; - rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; - *commandcode = i; + rmi_smb->mapping_table[i] = new_map; exit: mutex_unlock(&rmi_smb->mappingtable_mutex); - return retval; + if (retval < 0) + return retval; + + *commandcode = i; + return 0; } static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, @@ -282,19 +276,24 @@ static int rmi_smb_probe(struct i2c_client *client, { struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev); struct rmi_smb_xport *rmi_smb; - int retval; int smbus_version; + int error; + + if (!pdata) { + dev_err(&client->dev, "no platform data, aborting\n"); + return -ENOMEM; + } if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_FUNC_SMBUS_HOST_NOTIFY)) { dev_err(&client->dev, - "adapter does not support required functionality.\n"); + "adapter does not support required functionality\n"); return -ENODEV; } if (client->irq <= 0) { - dev_err(&client->dev, "no IRQ provided, giving up.\n"); + dev_err(&client->dev, "no IRQ provided, giving up\n"); return client->irq ? client->irq : -ENODEV; } @@ -303,12 +302,7 @@ static int rmi_smb_probe(struct i2c_client *client, if (!rmi_smb) return -ENOMEM; - if (!pdata) { - dev_err(&client->dev, "no platform data, aborting\n"); - return -ENOMEM; - } - - rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", + rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s\n", dev_name(&client->dev)); rmi_smb->client = client; @@ -321,34 +315,30 @@ static int rmi_smb_probe(struct i2c_client *client, rmi_smb->xport.proto_name = "smb2"; rmi_smb->xport.ops = &rmi_smb_ops; - retval = rmi_smb_get_version(rmi_smb); - if (retval < 0) - return retval; + smbus_version = rmi_smb_get_version(rmi_smb); + if (smbus_version < 0) + return smbus_version; - smbus_version = retval; rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d", smbus_version); if (smbus_version != 2) { - dev_err(&client->dev, "Unrecognized SMB version %d.\n", + dev_err(&client->dev, "Unrecognized SMB version %d\n", smbus_version); return -ENODEV; } i2c_set_clientdata(client, rmi_smb); - retval = rmi_register_transport_device(&rmi_smb->xport); - if (retval) { - dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n", - client->addr); - i2c_set_clientdata(client, NULL); - return retval; + dev_info(&client->dev, "registering SMbus-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_smb->xport); + if (error) { + dev_err(&client->dev, "failed to register sensor: %d\n", error); + return error; } - dev_info(&client->dev, "registered rmi smb driver at %#04x.\n", - client->addr); return 0; - } static int rmi_smb_remove(struct i2c_client *client) diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 69548d7d1f10..d97a85907ed6 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -370,7 +370,7 @@ static int rmi_spi_probe(struct spi_device *spi) struct rmi_spi_xport *rmi_spi; struct rmi_device_platform_data *pdata; struct rmi_device_platform_data *spi_pdata = spi->dev.platform_data; - int retval; + int error; if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) return -EINVAL; @@ -383,9 +383,9 @@ static int rmi_spi_probe(struct spi_device *spi) pdata = &rmi_spi->xport.pdata; if (spi->dev.of_node) { - retval = rmi_spi_of_probe(spi, pdata); - if (retval) - return retval; + error = rmi_spi_of_probe(spi, pdata); + if (error) + return error; } else if (spi_pdata) { *pdata = *spi_pdata; } @@ -396,10 +396,10 @@ static int rmi_spi_probe(struct spi_device *spi) if (pdata->spi_data.mode) spi->mode = pdata->spi_data.mode; - retval = spi_setup(spi); - if (retval < 0) { + error = spi_setup(spi); + if (error < 0) { dev_err(&spi->dev, "spi_setup failed!\n"); - return retval; + return error; } pdata->irq = spi->irq; @@ -413,32 +413,34 @@ static int rmi_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, rmi_spi); - retval = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE); - if (retval) - return retval; + error = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE); + if (error) + return error; /* * Setting the page to zero will (a) make sure the PSR is in a * known state, and (b) make sure we can talk to the device. */ - retval = rmi_set_page(rmi_spi, 0); - if (retval) { + error = rmi_set_page(rmi_spi, 0); + if (error) { dev_err(&spi->dev, "Failed to set page select to 0.\n"); - return retval; + return error; } - retval = rmi_register_transport_device(&rmi_spi->xport); - if (retval) { - dev_err(&spi->dev, "failed to register transport.\n"); - return retval; + dev_info(&spi->dev, "registering SPI-connected sensor\n"); + + error = rmi_register_transport_device(&rmi_spi->xport); + if (error) { + dev_err(&spi->dev, "failed to register sensor: %d\n", error); + return error; } - retval = devm_add_action_or_reset(&spi->dev, + + error = devm_add_action_or_reset(&spi->dev, rmi_spi_unregister_transport, rmi_spi); - if (retval) - return retval; + if (error) + return error; - dev_info(&spi->dev, "registered RMI SPI driver\n"); return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 1ca7f551e2da..30d6230d48f7 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -285,8 +285,8 @@ static int serio_queue_event(void *object, struct module *owner, } if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); + pr_warn("Can't get module reference, dropping event %d\n", + event_type); kfree(event); retval = -EINVAL; goto out; @@ -823,8 +823,8 @@ static void serio_attach_driver(struct serio_driver *drv) error = driver_attach(&drv->driver); if (error) - pr_warning("driver_attach() failed for %s with error %d\n", - drv->driver.name, error); + pr_warn("driver_attach() failed for %s with error %d\n", + drv->driver.name, error); } int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) @@ -953,12 +953,24 @@ static int serio_suspend(struct device *dev) static int serio_resume(struct device *dev) { struct serio *serio = to_serio_port(dev); + int error = -ENOENT; - /* - * Driver reconnect can take a while, so better let kseriod - * deal with it. - */ - serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); + mutex_lock(&serio->drv_mutex); + if (serio->drv && serio->drv->fast_reconnect) { + error = serio->drv->fast_reconnect(serio); + if (error && error != -ENOENT) + dev_warn(dev, "fast reconnect failed with error %d\n", + error); + } + mutex_unlock(&serio->drv_mutex); + + if (error) { + /* + * Driver reconnect can take a while, so better let + * kseriod deal with it. + */ + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); + } return 0; } diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c index e7409c45bdd0..12a3ad83296d 100644 --- a/drivers/input/sparse-keymap.c +++ b/drivers/input/sparse-keymap.c @@ -160,12 +160,12 @@ static int sparse_keymap_setkeycode(struct input_dev *dev, * @keymap: Keymap in form of array of &key_entry structures ending * with %KE_END type entry * @setup: Function that can be used to adjust keymap entries - * depending on device's deeds, may be %NULL + * depending on device's needs, may be %NULL * * The function calculates size and allocates copy of the original * keymap after which sets up input device event bits appropriately. - * Before destroying input device allocated keymap should be freed - * with a call to sparse_keymap_free(). + * The allocated copy of the keymap is automatically freed when it + * is no longer needed. */ int sparse_keymap_setup(struct input_dev *dev, const struct key_entry *keymap, @@ -180,19 +180,18 @@ int sparse_keymap_setup(struct input_dev *dev, for (e = keymap; e->type != KE_END; e++) map_size++; - map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL); + map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map), + GFP_KERNEL); if (!map) return -ENOMEM; - memcpy(map, keymap, map_size * sizeof(struct key_entry)); - for (i = 0; i < map_size; i++) { entry = &map[i]; if (setup) { error = setup(dev, entry); if (error) - goto err_out; + return error; } switch (entry->type) { @@ -221,10 +220,6 @@ int sparse_keymap_setup(struct input_dev *dev, dev->setkeycode = sparse_keymap_setkeycode; return 0; - - err_out: - kfree(map); - return error; } EXPORT_SYMBOL(sparse_keymap_setup); @@ -232,29 +227,13 @@ EXPORT_SYMBOL(sparse_keymap_setup); * sparse_keymap_free - free memory allocated for sparse keymap * @dev: Input device using sparse keymap * - * This function is used to free memory allocated by sparse keymap + * This function used to free memory allocated by sparse keymap * in an input device that was set up by sparse_keymap_setup(). - * NOTE: It is safe to cal this function while input device is - * still registered (however the drivers should care not to try to - * use freed keymap and thus have to shut off interrupts/polling - * before freeing the keymap). + * Since sparse_keymap_setup() now uses a managed allocation for the + * keymap copy, use of this function is deprecated. */ void sparse_keymap_free(struct input_dev *dev) { - unsigned long flags; - - /* - * Take event lock to prevent racing with input_get_keycode() - * and input_set_keycode() if we are called while input device - * is still registered. - */ - spin_lock_irqsave(&dev->event_lock, flags); - - kfree(dev->keycode); - dev->keycode = NULL; - dev->keycodemax = 0; - - spin_unlock_irqrestore(&dev->event_lock, flags); } EXPORT_SYMBOL(sparse_keymap_free); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 52458cfdf017..cf26ca49ae6d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -73,6 +73,7 @@ config TOUCHSCREEN_AD7879 config TOUCHSCREEN_AD7879_I2C tristate "support I2C bus connection" depends on TOUCHSCREEN_AD7879 && I2C + select REGMAP_I2C help Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus. @@ -82,6 +83,7 @@ config TOUCHSCREEN_AD7879_I2C config TOUCHSCREEN_AD7879_SPI tristate "support SPI bus connection" depends on TOUCHSCREEN_AD7879 && SPI_MASTER + select REGMAP_SPI help Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus. @@ -91,11 +93,11 @@ config TOUCHSCREEN_AD7879_SPI module will be called ad7879-spi. config TOUCHSCREEN_AR1021_I2C - tristate "Microchip AR1021 i2c touchscreen" + tristate "Microchip AR1020/1021 i2c touchscreen" depends on I2C && OF help - Say Y here if you have the Microchip AR1021 touchscreen controller - chip in your system. + Say Y here if you have the Microchip AR1020 or AR1021 touchscreen + controller chip in your system. If unsure, say N. @@ -1033,6 +1035,16 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_TSC2007_IIO + bool "IIO interface for external ADC input and temperature" + depends on TOUCHSCREEN_TSC2007 + depends on IIO=y || IIO=TOUCHSCREEN_TSC2007 + help + Saying Y here adds an iio interface to the tsc2007 which + provides values for the AUX input (used for e.g. battery + or ambient light monitoring), temperature and raw input + values. + config TOUCHSCREEN_W90X900 tristate "W90P910 touchscreen driver" depends on ARCH_W90X900 diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 96761ce2ee6d..18e476948e44 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -80,6 +80,8 @@ obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o +tsc2007-y := tsc2007_core.o +tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index 58f72e0246ab..49b902b10c5f 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -12,53 +12,22 @@ #include <linux/types.h> #include <linux/of.h> #include <linux/pm.h> +#include <linux/regmap.h> #include "ad7879.h" #define AD7879_DEVID 0x79 /* AD7879-1/AD7889-1 */ -/* All registers are word-sized. - * AD7879 uses a high-byte first convention. - */ -static int ad7879_i2c_read(struct device *dev, u8 reg) -{ - struct i2c_client *client = to_i2c_client(dev); - - return i2c_smbus_read_word_swapped(client, reg); -} - -static int ad7879_i2c_multi_read(struct device *dev, - u8 first_reg, u8 count, u16 *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - u8 idx; - - i2c_smbus_read_i2c_block_data(client, first_reg, count * 2, (u8 *)buf); - - for (idx = 0; idx < count; ++idx) - buf[idx] = swab16(buf[idx]); - - return 0; -} - -static int ad7879_i2c_write(struct device *dev, u8 reg, u16 val) -{ - struct i2c_client *client = to_i2c_client(dev); - - return i2c_smbus_write_word_swapped(client, reg, val); -} - -static const struct ad7879_bus_ops ad7879_i2c_bus_ops = { - .bustype = BUS_I2C, - .read = ad7879_i2c_read, - .multi_read = ad7879_i2c_multi_read, - .write = ad7879_i2c_write, +static const struct regmap_config ad7879_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = 15, }; static int ad7879_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct ad7879 *ts; + struct regmap *regmap; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA)) { @@ -66,23 +35,12 @@ static int ad7879_i2c_probe(struct i2c_client *client, return -EIO; } - ts = ad7879_probe(&client->dev, AD7879_DEVID, client->irq, - &ad7879_i2c_bus_ops); - if (IS_ERR(ts)) - return PTR_ERR(ts); - - i2c_set_clientdata(client, ts); - - return 0; -} - -static int ad7879_i2c_remove(struct i2c_client *client) -{ - struct ad7879 *ts = i2c_get_clientdata(client); - - ad7879_remove(ts); + regmap = devm_regmap_init_i2c(client, &ad7879_i2c_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - return 0; + return ad7879_probe(&client->dev, regmap, client->irq, + BUS_I2C, AD7879_DEVID); } static const struct i2c_device_id ad7879_id[] = { @@ -107,12 +65,11 @@ static struct i2c_driver ad7879_i2c_driver = { .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), }, .probe = ad7879_i2c_probe, - .remove = ad7879_i2c_remove, .id_table = ad7879_id, }; module_i2c_driver(ad7879_i2c_driver); -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("AD7879(-1) touchscreen I2C bus driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ad7879-spi.c b/drivers/input/touchscreen/ad7879-spi.c index d42b6b9af191..3457a5626d75 100644 --- a/drivers/input/touchscreen/ad7879-spi.c +++ b/drivers/input/touchscreen/ad7879-spi.c @@ -11,110 +11,28 @@ #include <linux/spi/spi.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/regmap.h> #include "ad7879.h" #define AD7879_DEVID 0x7A /* AD7879/AD7889 */ #define MAX_SPI_FREQ_HZ 5000000 -#define AD7879_CMD_MAGIC 0xE000 -#define AD7879_CMD_READ (1 << 10) -#define AD7879_CMD(reg) (AD7879_CMD_MAGIC | ((reg) & 0xF)) -#define AD7879_WRITECMD(reg) (AD7879_CMD(reg)) -#define AD7879_READCMD(reg) (AD7879_CMD(reg) | AD7879_CMD_READ) -/* - * ad7879_read/write are only used for initial setup and for sysfs controls. - * The main traffic is done in ad7879_collect(). - */ - -static int ad7879_spi_xfer(struct spi_device *spi, - u16 cmd, u8 count, u16 *tx_buf, u16 *rx_buf) -{ - struct spi_message msg; - struct spi_transfer *xfers; - void *spi_data; - u16 *command; - u16 *_rx_buf = _rx_buf; /* shut gcc up */ - u8 idx; - int ret; - - xfers = spi_data = kzalloc(sizeof(*xfers) * (count + 2), GFP_KERNEL); - if (!spi_data) - return -ENOMEM; - - spi_message_init(&msg); - - command = spi_data; - command[0] = cmd; - if (count == 1) { - /* ad7879_spi_{read,write} gave us buf on stack */ - command[1] = *tx_buf; - tx_buf = &command[1]; - _rx_buf = rx_buf; - rx_buf = &command[2]; - } - - ++xfers; - xfers[0].tx_buf = command; - xfers[0].len = 2; - spi_message_add_tail(&xfers[0], &msg); - ++xfers; - - for (idx = 0; idx < count; ++idx) { - if (rx_buf) - xfers[idx].rx_buf = &rx_buf[idx]; - if (tx_buf) - xfers[idx].tx_buf = &tx_buf[idx]; - xfers[idx].len = 2; - spi_message_add_tail(&xfers[idx], &msg); - } - - ret = spi_sync(spi, &msg); - - if (count == 1) - _rx_buf[0] = command[2]; - - kfree(spi_data); - - return ret; -} - -static int ad7879_spi_multi_read(struct device *dev, - u8 first_reg, u8 count, u16 *buf) -{ - struct spi_device *spi = to_spi_device(dev); +#define AD7879_CMD_MAGIC 0xE0 +#define AD7879_CMD_READ BIT(2) - return ad7879_spi_xfer(spi, AD7879_READCMD(first_reg), count, NULL, buf); -} - -static int ad7879_spi_read(struct device *dev, u8 reg) -{ - struct spi_device *spi = to_spi_device(dev); - u16 ret, dummy; - - return ad7879_spi_xfer(spi, AD7879_READCMD(reg), 1, &dummy, &ret) ? : ret; -} - -static int ad7879_spi_write(struct device *dev, u8 reg, u16 val) -{ - struct spi_device *spi = to_spi_device(dev); - u16 dummy; - - return ad7879_spi_xfer(spi, AD7879_WRITECMD(reg), 1, &val, &dummy); -} - -static const struct ad7879_bus_ops ad7879_spi_bus_ops = { - .bustype = BUS_SPI, - .read = ad7879_spi_read, - .multi_read = ad7879_spi_multi_read, - .write = ad7879_spi_write, +static const struct regmap_config ad7879_spi_regmap_config = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 15, + .read_flag_mask = AD7879_CMD_MAGIC | AD7879_CMD_READ, + .write_flag_mask = AD7879_CMD_MAGIC, }; static int ad7879_spi_probe(struct spi_device *spi) { - struct ad7879 *ts; - int err; + struct regmap *regmap; /* don't exceed max specified SPI CLK frequency */ if (spi->max_speed_hz > MAX_SPI_FREQ_HZ) { @@ -122,29 +40,11 @@ static int ad7879_spi_probe(struct spi_device *spi) return -EINVAL; } - spi->bits_per_word = 16; - err = spi_setup(spi); - if (err) { - dev_dbg(&spi->dev, "spi master doesn't support 16 bits/word\n"); - return err; - } - - ts = ad7879_probe(&spi->dev, AD7879_DEVID, spi->irq, &ad7879_spi_bus_ops); - if (IS_ERR(ts)) - return PTR_ERR(ts); - - spi_set_drvdata(spi, ts); - - return 0; -} - -static int ad7879_spi_remove(struct spi_device *spi) -{ - struct ad7879 *ts = spi_get_drvdata(spi); - - ad7879_remove(ts); + regmap = devm_regmap_init_spi(spi, &ad7879_spi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - return 0; + return ad7879_probe(&spi->dev, regmap, spi->irq, BUS_SPI, AD7879_DEVID); } #ifdef CONFIG_OF @@ -162,12 +62,11 @@ static struct spi_driver ad7879_spi_driver = { .of_match_table = of_match_ptr(ad7879_spi_dt_ids), }, .probe = ad7879_spi_probe, - .remove = ad7879_spi_remove, }; module_spi_driver(ad7879_spi_driver); -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("AD7879(-1) touchscreen SPI bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("spi:ad7879"); diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c index e16a44667da7..196028c45210 100644 --- a/drivers/input/touchscreen/ad7879.c +++ b/drivers/input/touchscreen/ad7879.c @@ -26,9 +26,9 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/property.h> +#include <linux/regmap.h> #include <linux/slab.h> -#include <linux/spi/spi.h> -#include <linux/i2c.h> #include <linux/gpio.h> #include <linux/input/touchscreen.h> @@ -106,8 +106,7 @@ enum { #define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50) struct ad7879 { - const struct ad7879_bus_ops *bops; - + struct regmap *regmap; struct device *dev; struct input_dev *input; struct timer_list timer; @@ -137,17 +136,32 @@ struct ad7879 { static int ad7879_read(struct ad7879 *ts, u8 reg) { - return ts->bops->read(ts->dev, reg); -} + unsigned int val; + int error; -static int ad7879_multi_read(struct ad7879 *ts, u8 first_reg, u8 count, u16 *buf) -{ - return ts->bops->multi_read(ts->dev, first_reg, count, buf); + error = regmap_read(ts->regmap, reg, &val); + if (error) { + dev_err(ts->dev, "failed to read register %#02x: %d\n", + reg, error); + return error; + } + + return val; } static int ad7879_write(struct ad7879 *ts, u8 reg, u16 val) { - return ts->bops->write(ts->dev, reg, val); + int error; + + error = regmap_write(ts->regmap, reg, val); + if (error) { + dev_err(ts->dev, + "failed to write %#04x to register %#02x: %d\n", + val, reg, error); + return error; + } + + return 0; } static int ad7879_report(struct ad7879 *ts) @@ -234,7 +248,8 @@ static irqreturn_t ad7879_irq(int irq, void *handle) { struct ad7879 *ts = handle; - ad7879_multi_read(ts, AD7879_REG_XPLUS, AD7879_NR_SENSE, ts->conversion_data); + regmap_bulk_read(ts->regmap, AD7879_REG_XPLUS, + ts->conversion_data, AD7879_NR_SENSE); if (!ad7879_report(ts)) mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT); @@ -440,23 +455,34 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip, static int ad7879_gpio_add(struct ad7879 *ts, const struct ad7879_platform_data *pdata) { + bool gpio_export; + int gpio_base; int ret = 0; + if (pdata) { + gpio_export = pdata->gpio_export; + gpio_base = pdata->gpio_base; + } else { + gpio_export = device_property_read_bool(ts->dev, + "gpio-controller"); + gpio_base = -1; + } + mutex_init(&ts->mutex); - if (pdata->gpio_export) { + if (gpio_export) { ts->gc.direction_input = ad7879_gpio_direction_input; ts->gc.direction_output = ad7879_gpio_direction_output; ts->gc.get = ad7879_gpio_get_value; ts->gc.set = ad7879_gpio_set_value; ts->gc.can_sleep = 1; - ts->gc.base = pdata->gpio_base; + ts->gc.base = gpio_base; ts->gc.ngpio = 1; ts->gc.label = "AD7879-GPIO"; ts->gc.owner = THIS_MODULE; ts->gc.parent = ts->dev; - ret = gpiochip_add_data(&ts->gc, ts); + ret = devm_gpiochip_add_data(ts->dev, &ts->gc, ts); if (ret) dev_err(ts->dev, "failed to register gpio %d\n", ts->gc.base); @@ -464,25 +490,12 @@ static int ad7879_gpio_add(struct ad7879 *ts, return ret; } - -static void ad7879_gpio_remove(struct ad7879 *ts) -{ - const struct ad7879_platform_data *pdata = dev_get_platdata(ts->dev); - - if (pdata && pdata->gpio_export) - gpiochip_remove(&ts->gc); - -} #else -static inline int ad7879_gpio_add(struct ad7879 *ts, - const struct ad7879_platform_data *pdata) +static int ad7879_gpio_add(struct ad7879 *ts, + const struct ad7879_platform_data *pdata) { return 0; } - -static inline void ad7879_gpio_remove(struct ad7879 *ts) -{ -} #endif static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) @@ -511,8 +524,15 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts) return 0; } -struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, - const struct ad7879_bus_ops *bops) +static void ad7879_cleanup_sysfs(void *_ts) +{ + struct ad7879 *ts = _ts; + + sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); +} + +int ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid) { struct ad7879_platform_data *pdata = dev_get_platdata(dev); struct ad7879 *ts; @@ -520,14 +540,14 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, int err; u16 revid; - if (!irq) { + if (irq <= 0) { dev_err(dev, "No IRQ specified\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); if (!ts) - return ERR_PTR(-ENOMEM); + return -ENOMEM; if (pdata) { /* Platform data use swapped axis (backward compatibility) */ @@ -540,23 +560,22 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, ts->averaging = pdata->averaging; ts->pen_down_acc_interval = pdata->pen_down_acc_interval; ts->median = pdata->median; - } else if (dev->of_node) { - ad7879_parse_dt(dev, ts); } else { - dev_err(dev, "No platform data\n"); - return ERR_PTR(-EINVAL); + err = ad7879_parse_dt(dev, ts); + if (err) + return err; } input_dev = devm_input_allocate_device(dev); if (!input_dev) { dev_err(dev, "Failed to allocate input device\n"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } - ts->bops = bops; ts->dev = dev; ts->input = input_dev; ts->irq = irq; + ts->regmap = regmap; setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev)); @@ -564,20 +583,14 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, input_dev->name = "AD7879 Touchscreen"; input_dev->phys = ts->phys; input_dev->dev.parent = dev; - input_dev->id.bustype = bops->bustype; + input_dev->id.bustype = bustype; input_dev->open = ad7879_open; input_dev->close = ad7879_close; input_set_drvdata(input_dev, ts); - __set_bit(EV_ABS, input_dev->evbit); - __set_bit(ABS_X, input_dev->absbit); - __set_bit(ABS_Y, input_dev->absbit); - __set_bit(ABS_PRESSURE, input_dev->absbit); - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(BTN_TOUCH, input_dev->keybit); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); if (pdata) { input_set_abs_params(input_dev, ABS_X, @@ -595,17 +608,18 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, } else { input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); + input_set_capability(input_dev, EV_ABS, ABS_PRESSURE); touchscreen_parse_properties(input_dev, false, NULL); if (!input_abs_get_max(input_dev, ABS_PRESSURE)) { dev_err(dev, "Touchscreen pressure is not specified\n"); - return ERR_PTR(-EINVAL); + return -EINVAL; } } err = ad7879_write(ts, AD7879_REG_CTRL2, AD7879_RESET); if (err < 0) { dev_err(dev, "Failed to write %s\n", input_dev->name); - return ERR_PTR(err); + return err; } revid = ad7879_read(ts, AD7879_REG_REVID); @@ -614,7 +628,7 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, if (input_dev->id.product != devid) { dev_err(dev, "Failed to probe %s (%x vs %x)\n", input_dev->name, devid, revid); - return ERR_PTR(-ENODEV); + return -ENODEV; } ts->cmd_crtl3 = AD7879_YPLUS_BIT | @@ -639,43 +653,33 @@ struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned int irq, dev_name(dev), ts); if (err) { dev_err(dev, "Failed to request IRQ: %d\n", err); - return ERR_PTR(err); + return err; } __ad7879_disable(ts); err = sysfs_create_group(&dev->kobj, &ad7879_attr_group); if (err) - goto err_out; + return err; - if (pdata) { - err = ad7879_gpio_add(ts, pdata); - if (err) - goto err_remove_attr; - } + err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts); + if (err) + return err; + + err = ad7879_gpio_add(ts, pdata); + if (err) + return err; err = input_register_device(input_dev); if (err) - goto err_remove_gpio; + return err; - return ts; + dev_set_drvdata(dev, ts); -err_remove_gpio: - ad7879_gpio_remove(ts); -err_remove_attr: - sysfs_remove_group(&dev->kobj, &ad7879_attr_group); -err_out: - return ERR_PTR(err); + return 0; } EXPORT_SYMBOL(ad7879_probe); -void ad7879_remove(struct ad7879 *ts) -{ - ad7879_gpio_remove(ts); - sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group); -} -EXPORT_SYMBOL(ad7879_remove); - -MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); MODULE_DESCRIPTION("AD7879(-1) touchscreen Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/ad7879.h b/drivers/input/touchscreen/ad7879.h index 6fd13c48d373..7e43066a4b68 100644 --- a/drivers/input/touchscreen/ad7879.h +++ b/drivers/input/touchscreen/ad7879.h @@ -11,20 +11,12 @@ #include <linux/types.h> -struct ad7879; struct device; - -struct ad7879_bus_ops { - u16 bustype; - int (*read)(struct device *dev, u8 reg); - int (*multi_read)(struct device *dev, u8 first_reg, u8 count, u16 *buf); - int (*write)(struct device *dev, u8 reg, u16 val); -}; +struct regmap; extern const struct dev_pm_ops ad7879_pm_ops; -struct ad7879 *ad7879_probe(struct device *dev, u8 devid, unsigned irq, - const struct ad7879_bus_ops *bops); -void ad7879_remove(struct ad7879 *); +int ad7879_probe(struct device *dev, struct regmap *regmap, + int irq, u16 bustype, u8 devid); #endif diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f5793e3d945f..735a0be1ad95 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -871,7 +871,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) msecs_to_jiffies(TS_POLL_PERIOD)); } - if (ts->pendown) { + if (ts->pendown && !ts->stopped) { struct input_dev *input = ts->input; input_report_key(input, BTN_TOUCH, 0); diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 6562b17117f7..f9dcbd63e598 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -1,11 +1,12 @@ /* - * Microchip AR1021 driver for I2C + * Microchip AR1020 and AR1021 driver for I2C * * Author: Christian Gmeiner <christian.gmeiner@gmail.com> * * License: GPLv2 as published by the FSF. */ +#include <linux/bitops.h> #include <linux/module.h> #include <linux/input.h> #include <linux/of.h> @@ -18,6 +19,10 @@ #define AR1021_MAX_X 4095 #define AR1021_MAX_Y 4095 +#define AR1021_CMD 0x55 + +#define AR1021_CMD_ENABLE_TOUCH 0x12 + struct ar1021_i2c { struct i2c_client *client; struct input_dev *input; @@ -33,12 +38,12 @@ static irqreturn_t ar1021_i2c_irq(int irq, void *dev_id) int retval; retval = i2c_master_recv(ar1021->client, - ar1021->data, sizeof(ar1021->data)); + ar1021->data, sizeof(ar1021->data)); if (retval != sizeof(ar1021->data)) goto out; /* sync bit set ? */ - if ((data[0] & 0x80) == 0) + if (!(data[0] & BIT(7))) goto out; button = data[0] & BIT(0); @@ -56,8 +61,19 @@ out: static int ar1021_i2c_open(struct input_dev *dev) { + static const u8 cmd_enable_touch[] = { + AR1021_CMD, + 0x01, /* number of bytes after this */ + AR1021_CMD_ENABLE_TOUCH + }; struct ar1021_i2c *ar1021 = input_get_drvdata(dev); struct i2c_client *client = ar1021->client; + int error; + + error = i2c_master_send(ar1021->client, cmd_enable_touch, + sizeof(cmd_enable_touch)); + if (error < 0) + return error; enable_irq(client->irq); @@ -73,7 +89,7 @@ static void ar1021_i2c_close(struct input_dev *dev) } static int ar1021_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { struct ar1021_i2c *ar1021; struct input_dev *input; @@ -109,7 +125,7 @@ static int ar1021_i2c_probe(struct i2c_client *client, error = devm_request_threaded_irq(&client->dev, client->irq, NULL, ar1021_i2c_irq, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, + IRQF_ONESHOT, "ar1021_i2c", ar1021); if (error) { dev_err(&client->dev, @@ -151,7 +167,7 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "MICROCHIP_AR1021_I2C", 0 }, + { "ar1021", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); @@ -175,5 +191,5 @@ static struct i2c_driver ar1021_i2c_driver = { module_i2c_driver(ar1021_i2c_driver); MODULE_AUTHOR("Christian Gmeiner <christian.gmeiner@gmail.com>"); -MODULE_DESCRIPTION("Microchip AR1021 I2C Driver"); +MODULE_DESCRIPTION("Microchip AR1020 and AR1021 I2C Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 16023867b9da..2facad75eb6d 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -31,9 +31,9 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/timer.h> -#include <linux/gpio.h> -#include <linux/input/eeti_ts.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> +#include <asm/unaligned.h> static bool flip_x; module_param(flip_x, bool, 0644); @@ -43,54 +43,31 @@ static bool flip_y; module_param(flip_y, bool, 0644); MODULE_PARM_DESC(flip_y, "flip y coordinate"); -struct eeti_ts_priv { +struct eeti_ts { struct i2c_client *client; struct input_dev *input; - struct work_struct work; - struct mutex mutex; - int irq_gpio, irq, irq_active_high; + struct gpio_desc *attn_gpio; + bool running; }; #define EETI_TS_BITDEPTH (11) #define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1) -#define REPORT_BIT_PRESSED (1 << 0) -#define REPORT_BIT_AD0 (1 << 1) -#define REPORT_BIT_AD1 (1 << 2) -#define REPORT_BIT_HAS_PRESSURE (1 << 6) +#define REPORT_BIT_PRESSED BIT(0) +#define REPORT_BIT_AD0 BIT(1) +#define REPORT_BIT_AD1 BIT(2) +#define REPORT_BIT_HAS_PRESSURE BIT(6) #define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) -static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv) +static void eeti_ts_report_event(struct eeti_ts *eeti, u8 *buf) { - return gpio_get_value(priv->irq_gpio) == priv->irq_active_high; -} - -static void eeti_ts_read(struct work_struct *work) -{ - char buf[6]; - unsigned int x, y, res, pressed, to = 100; - struct eeti_ts_priv *priv = - container_of(work, struct eeti_ts_priv, work); + unsigned int res; + u16 x, y; - mutex_lock(&priv->mutex); - - while (eeti_ts_irq_active(priv) && --to) - i2c_master_recv(priv->client, buf, sizeof(buf)); - - if (!to) { - dev_err(&priv->client->dev, - "unable to clear IRQ - line stuck?\n"); - goto out; - } - - /* drop non-report packets */ - if (!(buf[0] & 0x80)) - goto out; - - pressed = buf[0] & REPORT_BIT_PRESSED; res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); - x = buf[2] | (buf[1] << 8); - y = buf[4] | (buf[3] << 8); + + x = get_unaligned_be16(&buf[1]); + y = get_unaligned_be16(&buf[3]); /* fix the range to 11 bits */ x >>= res - EETI_TS_BITDEPTH; @@ -103,65 +80,78 @@ static void eeti_ts_read(struct work_struct *work) y = EETI_MAXVAL - y; if (buf[0] & REPORT_BIT_HAS_PRESSURE) - input_report_abs(priv->input, ABS_PRESSURE, buf[5]); + input_report_abs(eeti->input, ABS_PRESSURE, buf[5]); - input_report_abs(priv->input, ABS_X, x); - input_report_abs(priv->input, ABS_Y, y); - input_report_key(priv->input, BTN_TOUCH, !!pressed); - input_sync(priv->input); - -out: - mutex_unlock(&priv->mutex); + input_report_abs(eeti->input, ABS_X, x); + input_report_abs(eeti->input, ABS_Y, y); + input_report_key(eeti->input, BTN_TOUCH, buf[0] & REPORT_BIT_PRESSED); + input_sync(eeti->input); } static irqreturn_t eeti_ts_isr(int irq, void *dev_id) { - struct eeti_ts_priv *priv = dev_id; + struct eeti_ts *eeti = dev_id; + int len; + int error; + char buf[6]; - /* postpone I2C transactions as we are atomic */ - schedule_work(&priv->work); + do { + len = i2c_master_recv(eeti->client, buf, sizeof(buf)); + if (len != sizeof(buf)) { + error = len < 0 ? len : -EIO; + dev_err(&eeti->client->dev, + "failed to read touchscreen data: %d\n", + error); + break; + } + + if (buf[0] & 0x80) { + /* Motion packet */ + eeti_ts_report_event(eeti, buf); + } + } while (eeti->running && + eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio)); return IRQ_HANDLED; } -static void eeti_ts_start(struct eeti_ts_priv *priv) +static void eeti_ts_start(struct eeti_ts *eeti) { - enable_irq(priv->irq); - - /* Read the events once to arm the IRQ */ - eeti_ts_read(&priv->work); + eeti->running = true; + wmb(); + enable_irq(eeti->client->irq); } -static void eeti_ts_stop(struct eeti_ts_priv *priv) +static void eeti_ts_stop(struct eeti_ts *eeti) { - disable_irq(priv->irq); - cancel_work_sync(&priv->work); + eeti->running = false; + wmb(); + disable_irq(eeti->client->irq); } static int eeti_ts_open(struct input_dev *dev) { - struct eeti_ts_priv *priv = input_get_drvdata(dev); + struct eeti_ts *eeti = input_get_drvdata(dev); - eeti_ts_start(priv); + eeti_ts_start(eeti); return 0; } static void eeti_ts_close(struct input_dev *dev) { - struct eeti_ts_priv *priv = input_get_drvdata(dev); + struct eeti_ts *eeti = input_get_drvdata(dev); - eeti_ts_stop(priv); + eeti_ts_stop(eeti); } static int eeti_ts_probe(struct i2c_client *client, - const struct i2c_device_id *idp) + const struct i2c_device_id *idp) { - struct eeti_ts_platform_data *pdata = dev_get_platdata(&client->dev); - struct eeti_ts_priv *priv; + struct device *dev = &client->dev; + struct eeti_ts *eeti; struct input_dev *input; - unsigned int irq_flags; - int err = -ENOMEM; + int error; /* * In contrast to what's described in the datasheet, there seems @@ -170,21 +160,19 @@ static int eeti_ts_probe(struct i2c_client *client, * for interrupts to occur. */ - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, "failed to allocate driver data\n"); + eeti = devm_kzalloc(dev, sizeof(*eeti), GFP_KERNEL); + if (!eeti) { + dev_err(dev, "failed to allocate driver data\n"); return -ENOMEM; } - mutex_init(&priv->mutex); - input = input_allocate_device(); + input = devm_input_allocate_device(dev); if (!input) { - dev_err(&client->dev, "Failed to allocate input device.\n"); - goto err1; + dev_err(dev, "Failed to allocate input device.\n"); + return -ENOMEM; } - input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOUCH); input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0); input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0); @@ -192,71 +180,38 @@ static int eeti_ts_probe(struct i2c_client *client, input->name = client->name; input->id.bustype = BUS_I2C; - input->dev.parent = &client->dev; input->open = eeti_ts_open; input->close = eeti_ts_close; - priv->client = client; - priv->input = input; - priv->irq_gpio = pdata->irq_gpio; - priv->irq = gpio_to_irq(pdata->irq_gpio); - - err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name); - if (err < 0) - goto err1; - - priv->irq_active_high = pdata->irq_active_high; - - irq_flags = priv->irq_active_high ? - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + eeti->client = client; + eeti->input = input; - INIT_WORK(&priv->work, eeti_ts_read); - i2c_set_clientdata(client, priv); - input_set_drvdata(input, priv); + eeti->attn_gpio = devm_gpiod_get_optional(dev, "attn", GPIOD_IN); + if (IS_ERR(eeti->attn_gpio)) + return PTR_ERR(eeti->attn_gpio); - err = input_register_device(input); - if (err) - goto err2; + i2c_set_clientdata(client, eeti); + input_set_drvdata(input, eeti); - err = request_irq(priv->irq, eeti_ts_isr, irq_flags, - client->name, priv); - if (err) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - goto err3; + error = devm_request_threaded_irq(dev, client->irq, + NULL, eeti_ts_isr, + IRQF_ONESHOT, + client->name, eeti); + if (error) { + dev_err(dev, "Unable to request touchscreen IRQ: %d\n", + error); + return error; } /* * Disable the device for now. It will be enabled once the * input device is opened. */ - eeti_ts_stop(priv); - - return 0; - -err3: - input_unregister_device(input); - input = NULL; /* so we dont try to free it below */ -err2: - gpio_free(pdata->irq_gpio); -err1: - input_free_device(input); - kfree(priv); - return err; -} - -static int eeti_ts_remove(struct i2c_client *client) -{ - struct eeti_ts_priv *priv = i2c_get_clientdata(client); - - free_irq(priv->irq, priv); - /* - * eeti_ts_stop() leaves IRQ disabled. We need to re-enable it - * so that device still works if we reload the driver. - */ - enable_irq(priv->irq); + eeti_ts_stop(eeti); - input_unregister_device(priv->input); - kfree(priv); + error = input_register_device(input); + if (error) + return error; return 0; } @@ -264,18 +219,18 @@ static int eeti_ts_remove(struct i2c_client *client) static int __maybe_unused eeti_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct eeti_ts_priv *priv = i2c_get_clientdata(client); - struct input_dev *input_dev = priv->input; + struct eeti_ts *eeti = i2c_get_clientdata(client); + struct input_dev *input_dev = eeti->input; mutex_lock(&input_dev->mutex); if (input_dev->users) - eeti_ts_stop(priv); + eeti_ts_stop(eeti); mutex_unlock(&input_dev->mutex); if (device_may_wakeup(&client->dev)) - enable_irq_wake(priv->irq); + enable_irq_wake(client->irq); return 0; } @@ -283,16 +238,16 @@ static int __maybe_unused eeti_ts_suspend(struct device *dev) static int __maybe_unused eeti_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct eeti_ts_priv *priv = i2c_get_clientdata(client); - struct input_dev *input_dev = priv->input; + struct eeti_ts *eeti = i2c_get_clientdata(client); + struct input_dev *input_dev = eeti->input; if (device_may_wakeup(&client->dev)) - disable_irq_wake(priv->irq); + disable_irq_wake(client->irq); mutex_lock(&input_dev->mutex); if (input_dev->users) - eeti_ts_start(priv); + eeti_ts_start(eeti); mutex_unlock(&input_dev->mutex); @@ -313,7 +268,6 @@ static struct i2c_driver eeti_ts_driver = { .pm = &eeti_ts_pm, }, .probe = eeti_ts_probe, - .remove = eeti_ts_remove, .id_table = eeti_ts_id, }; diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 7098e0a47019..ee82a975bfd2 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -337,11 +337,20 @@ static int imx6ul_tsc_open(struct input_dev *input_dev) dev_err(tsc->dev, "Could not prepare or enable the tsc clock: %d\n", err); - clk_disable_unprepare(tsc->adc_clk); - return err; + goto disable_adc_clk; } - return imx6ul_tsc_init(tsc); + err = imx6ul_tsc_init(tsc); + if (err) + goto disable_tsc_clk; + + return 0; + +disable_tsc_clk: + clk_disable_unprepare(tsc->tsc_clk); +disable_adc_clk: + clk_disable_unprepare(tsc->adc_clk); + return err; } static void imx6ul_tsc_close(struct input_dev *input_dev) diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index e0baa7de4102..4eb31ec10b18 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -142,11 +142,14 @@ static void lpc32xx_stop_tsc(struct lpc32xx_tsc *tsc) clk_disable_unprepare(tsc->clk); } -static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) +static int lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) { u32 tmp; + int err; - clk_prepare_enable(tsc->clk); + err = clk_prepare_enable(tsc->clk); + if (err) + return err; tmp = tsc_readl(tsc, LPC32XX_TSC_CON) & ~LPC32XX_TSC_ADCCON_POWER_UP; @@ -184,15 +187,15 @@ static void lpc32xx_setup_tsc(struct lpc32xx_tsc *tsc) /* Enable automatic ts event capture */ tsc_writel(tsc, LPC32XX_TSC_CON, tmp | LPC32XX_TSC_ADCCON_AUTO_EN); + + return 0; } static int lpc32xx_ts_open(struct input_dev *dev) { struct lpc32xx_tsc *tsc = input_get_drvdata(dev); - lpc32xx_setup_tsc(tsc); - - return 0; + return lpc32xx_setup_tsc(tsc); } static void lpc32xx_ts_close(struct input_dev *dev) diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index a595ae5284e3..72ca3efb5781 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -224,9 +224,16 @@ static const struct i2c_device_id max11801_ts_id[] = { }; MODULE_DEVICE_TABLE(i2c, max11801_ts_id); +static const struct of_device_id max11801_ts_dt_ids[] = { + { .compatible = "maxim,max11801" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, max11801_ts_dt_ids); + static struct i2c_driver max11801_ts_driver = { .driver = { .name = "max11801_ts", + .of_match_table = max11801_ts_dt_ids, }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 703d7f983d0a..05108c2fea93 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -253,10 +253,21 @@ static int mip4_get_fw_version(struct mip4_ts *ts) */ static int mip4_query_device(struct mip4_ts *ts) { + union i2c_smbus_data dummy; int error; u8 cmd[2]; u8 buf[14]; + /* + * Make sure there is something at this address as we do not + * consider subsequent failures as fatal. + */ + if (i2c_smbus_xfer(ts->client->adapter, ts->client->addr, + 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&ts->client->dev, "nothing at this address\n"); + return -ENXIO; + } + /* Product name */ cmd[0] = MIP4_R0_INFO; cmd[1] = MIP4_R1_INFO_PRODUCT_NAME; diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 404830a4a366..813dd68a5c82 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -580,12 +580,25 @@ static const struct acpi_device_id silead_ts_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match); #endif +#ifdef CONFIG_OF +static const struct of_device_id silead_ts_of_match[] = { + { .compatible = "silead,gsl1680" }, + { .compatible = "silead,gsl1688" }, + { .compatible = "silead,gsl3670" }, + { .compatible = "silead,gsl3675" }, + { .compatible = "silead,gsl3692" }, + { }, +}; +MODULE_DEVICE_TABLE(of, silead_ts_of_match); +#endif + static struct i2c_driver silead_ts_driver = { .probe = silead_ts_probe, .id_table = silead_ts_id, .driver = { .name = SILEAD_TS_NAME, .acpi_match_table = ACPI_PTR(silead_ts_acpi_match), + .of_match_table = of_match_ptr(silead_ts_of_match), .pm = &silead_ts_pm, }, }; diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 4c0eecae065c..128e5bd74720 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -369,7 +369,7 @@ static void sur40_poll(struct input_polled_dev *polldev) * packet ID will usually increase in the middle of a series * instead of at the end. */ - if (packet_id != header->packet_id) + if (packet_id != le32_to_cpu(header->packet_id)) dev_dbg(sur40->dev, "packet ID mismatch\n"); packet_blobs = result / sizeof(struct sur40_blob); diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c index a340bfccdfb6..75170a7439b1 100644 --- a/drivers/input/touchscreen/tps6507x-ts.c +++ b/drivers/input/touchscreen/tps6507x-ts.c @@ -226,7 +226,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev) */ init_data = tps_board->tps6507x_ts_init_data; - tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL); + tsc = devm_kzalloc(&pdev->dev, sizeof(struct tps6507x_ts), GFP_KERNEL); if (!tsc) { dev_err(tps6507x_dev->dev, "failed to allocate driver data\n"); return -ENOMEM; @@ -240,11 +240,10 @@ static int tps6507x_ts_probe(struct platform_device *pdev) snprintf(tsc->phys, sizeof(tsc->phys), "%s/input0", dev_name(tsc->dev)); - poll_dev = input_allocate_polled_device(); + poll_dev = devm_input_allocate_polled_device(&pdev->dev); if (!poll_dev) { dev_err(tsc->dev, "Failed to allocate polled input device.\n"); - error = -ENOMEM; - goto err_free_mem; + return -ENOMEM; } tsc->poll_dev = poll_dev; @@ -274,32 +273,11 @@ static int tps6507x_ts_probe(struct platform_device *pdev) error = tps6507x_adc_standby(tsc); if (error) - goto err_free_polled_dev; + return error; error = input_register_polled_device(poll_dev); if (error) - goto err_free_polled_dev; - - platform_set_drvdata(pdev, tsc); - - return 0; - -err_free_polled_dev: - input_free_polled_device(poll_dev); -err_free_mem: - kfree(tsc); - return error; -} - -static int tps6507x_ts_remove(struct platform_device *pdev) -{ - struct tps6507x_ts *tsc = platform_get_drvdata(pdev); - struct input_polled_dev *poll_dev = tsc->poll_dev; - - input_unregister_polled_device(poll_dev); - input_free_polled_device(poll_dev); - - kfree(tsc); + return error; return 0; } @@ -309,7 +287,6 @@ static struct platform_driver tps6507x_ts_driver = { .name = "tps6507x-ts", }, .probe = tps6507x_ts_probe, - .remove = tps6507x_ts_remove, }; module_platform_driver(tps6507x_ts_driver); diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h new file mode 100644 index 000000000000..30fdf5b04a6b --- /dev/null +++ b/drivers/input/touchscreen/tsc2007.h @@ -0,0 +1,101 @@ + +/* + * Copyright (c) 2008 MtekVision Co., Ltd. + * Kwangwoo Lee <kwlee@mtekvision.com> + * + * Using code from: + * - ads7846.c + * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * - corgi_ts.c + * Copyright (C) 2004-2005 Richard Purdie + * - omap_ts.[hc], ads7846.h, ts_osk.c + * Copyright (C) 2002 MontaVista Software + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2005 Dirk Behme + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _TSC2007_H +#define _TSC2007_H + +#define TSC2007_MEASURE_TEMP0 (0x0 << 4) +#define TSC2007_MEASURE_AUX (0x2 << 4) +#define TSC2007_MEASURE_TEMP1 (0x4 << 4) +#define TSC2007_ACTIVATE_XN (0x8 << 4) +#define TSC2007_ACTIVATE_YN (0x9 << 4) +#define TSC2007_ACTIVATE_YP_XN (0xa << 4) +#define TSC2007_SETUP (0xb << 4) +#define TSC2007_MEASURE_X (0xc << 4) +#define TSC2007_MEASURE_Y (0xd << 4) +#define TSC2007_MEASURE_Z1 (0xe << 4) +#define TSC2007_MEASURE_Z2 (0xf << 4) + +#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2) +#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2) +#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2) +#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2) + +#define TSC2007_12BIT (0x0 << 1) +#define TSC2007_8BIT (0x1 << 1) + +#define MAX_12BIT ((1 << 12) - 1) + +#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0) + +#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y) +#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1) +#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2) +#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X) +#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN) + +struct ts_event { + u16 x; + u16 y; + u16 z1, z2; +}; + +struct tsc2007 { + struct input_dev *input; + char phys[32]; + + struct i2c_client *client; + + u16 model; + u16 x_plate_ohms; + u16 max_rt; + unsigned long poll_period; /* in jiffies */ + int fuzzx; + int fuzzy; + int fuzzz; + + unsigned int gpio; + int irq; + + wait_queue_head_t wait; + bool stopped; + + int (*get_pendown_state)(struct device *); + void (*clear_penirq)(void); + + struct mutex mlock; +}; + +int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd); +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc); +bool tsc2007_is_pen_down(struct tsc2007 *ts); + +#if IS_ENABLED(CONFIG_TOUCHSCREEN_TSC2007_IIO) +/* defined in tsc2007_iio.c */ +int tsc2007_iio_configure(struct tsc2007 *ts); +#else +static inline int tsc2007_iio_configure(struct tsc2007 *ts) +{ + return 0; +} +#endif /* CONFIG_TOUCHSCREEN_TSC2007_IIO */ + +#endif /* _TSC2007_H */ diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007_core.c index 5d0cd51c6f41..fc7384936011 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -27,70 +27,10 @@ #include <linux/i2c.h> #include <linux/i2c/tsc2007.h> #include <linux/of_device.h> -#include <linux/of.h> #include <linux/of_gpio.h> +#include "tsc2007.h" -#define TSC2007_MEASURE_TEMP0 (0x0 << 4) -#define TSC2007_MEASURE_AUX (0x2 << 4) -#define TSC2007_MEASURE_TEMP1 (0x4 << 4) -#define TSC2007_ACTIVATE_XN (0x8 << 4) -#define TSC2007_ACTIVATE_YN (0x9 << 4) -#define TSC2007_ACTIVATE_YP_XN (0xa << 4) -#define TSC2007_SETUP (0xb << 4) -#define TSC2007_MEASURE_X (0xc << 4) -#define TSC2007_MEASURE_Y (0xd << 4) -#define TSC2007_MEASURE_Z1 (0xe << 4) -#define TSC2007_MEASURE_Z2 (0xf << 4) - -#define TSC2007_POWER_OFF_IRQ_EN (0x0 << 2) -#define TSC2007_ADC_ON_IRQ_DIS0 (0x1 << 2) -#define TSC2007_ADC_OFF_IRQ_EN (0x2 << 2) -#define TSC2007_ADC_ON_IRQ_DIS1 (0x3 << 2) - -#define TSC2007_12BIT (0x0 << 1) -#define TSC2007_8BIT (0x1 << 1) - -#define MAX_12BIT ((1 << 12) - 1) - -#define ADC_ON_12BIT (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0) - -#define READ_Y (ADC_ON_12BIT | TSC2007_MEASURE_Y) -#define READ_Z1 (ADC_ON_12BIT | TSC2007_MEASURE_Z1) -#define READ_Z2 (ADC_ON_12BIT | TSC2007_MEASURE_Z2) -#define READ_X (ADC_ON_12BIT | TSC2007_MEASURE_X) -#define PWRDOWN (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN) - -struct ts_event { - u16 x; - u16 y; - u16 z1, z2; -}; - -struct tsc2007 { - struct input_dev *input; - char phys[32]; - - struct i2c_client *client; - - u16 model; - u16 x_plate_ohms; - u16 max_rt; - unsigned long poll_period; /* in jiffies */ - int fuzzx; - int fuzzy; - int fuzzz; - - unsigned gpio; - int irq; - - wait_queue_head_t wait; - bool stopped; - - int (*get_pendown_state)(struct device *); - void (*clear_penirq)(void); -}; - -static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) +int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) { s32 data; u16 val; @@ -128,7 +68,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) tsc2007_xfer(tsc, PWRDOWN); } -static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc) { u32 rt = 0; @@ -137,7 +77,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) tc->x = 0; if (likely(tc->x && tc->z1)) { - /* compute touch pressure resistance using equation #1 */ + /* compute touch resistance using equation #1 */ rt = tc->z2 - tc->z1; rt *= tc->x; rt *= tsc->x_plate_ohms; @@ -148,7 +88,7 @@ static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) return rt; } -static bool tsc2007_is_pen_down(struct tsc2007 *ts) +bool tsc2007_is_pen_down(struct tsc2007 *ts) { /* * NOTE: We can't rely on the pressure to determine the pen down @@ -180,9 +120,12 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) while (!ts->stopped && tsc2007_is_pen_down(ts)) { /* pen is down, continue with the measurement */ + + mutex_lock(&ts->mlock); tsc2007_read_values(ts, &tc); + mutex_unlock(&ts->mlock); - rt = tsc2007_calculate_pressure(ts, &tc); + rt = tsc2007_calculate_resistance(ts, &tc); if (!rt && !ts->get_pendown_state) { /* @@ -195,9 +138,11 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) if (rt <= ts->max_rt) { dev_dbg(&ts->client->dev, - "DOWN point(%4d,%4d), pressure (%4u)\n", + "DOWN point(%4d,%4d), resistance (%4u)\n", tc.x, tc.y, rt); + 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); @@ -375,7 +320,8 @@ static void tsc2007_call_exit_platform_hw(void *data) static int tsc2007_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); + const struct tsc2007_platform_data *pdata = + dev_get_platdata(&client->dev); struct tsc2007 *ts; struct input_dev *input_dev; int err; @@ -404,7 +350,9 @@ static int tsc2007_probe(struct i2c_client *client, ts->client = client; ts->irq = client->irq; ts->input = input_dev; + init_waitqueue_head(&ts->wait); + mutex_init(&ts->mlock); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -418,8 +366,7 @@ static int tsc2007_probe(struct i2c_client *client, input_set_drvdata(input_dev, ts); - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); @@ -455,6 +402,14 @@ static int tsc2007_probe(struct i2c_client *client, tsc2007_stop(ts); + /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + dev_err(&client->dev, + "Failed to setup chip: %d\n", err); + return err; /* chip does not respond */ + } + err = input_register_device(input_dev); if (err) { dev_err(&client->dev, @@ -462,6 +417,13 @@ static int tsc2007_probe(struct i2c_client *client, return err; } + err = tsc2007_iio_configure(ts); + if (err) { + dev_err(&client->dev, + "Failed to register with IIO: %d\n", err); + return err; + } + return 0; } diff --git a/drivers/input/touchscreen/tsc2007_iio.c b/drivers/input/touchscreen/tsc2007_iio.c new file mode 100644 index 000000000000..27b25a9fce83 --- /dev/null +++ b/drivers/input/touchscreen/tsc2007_iio.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016 Golden Delicious Comp. GmbH&Co. KG + * Nikolaus Schaller <hns@goldelico.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include "tsc2007.h" + +struct tsc2007_iio { + struct tsc2007 *ts; +}; + +#define TSC2007_CHAN_IIO(_chan, _name, _type, _chan_info) \ +{ \ + .datasheet_name = _name, \ + .type = _type, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(_chan_info), \ + .indexed = 1, \ + .channel = _chan, \ +} + +static const struct iio_chan_spec tsc2007_iio_channel[] = { + TSC2007_CHAN_IIO(0, "x", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(1, "y", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(2, "z1", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(3, "z2", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(4, "adc", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(5, "rt", IIO_VOLTAGE, IIO_CHAN_INFO_RAW), /* Ohms? */ + TSC2007_CHAN_IIO(6, "pen", IIO_PRESSURE, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(7, "temp0", IIO_TEMP, IIO_CHAN_INFO_RAW), + TSC2007_CHAN_IIO(8, "temp1", IIO_TEMP, IIO_CHAN_INFO_RAW), +}; + +static int tsc2007_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct tsc2007_iio *iio = iio_priv(indio_dev); + struct tsc2007 *tsc = iio->ts; + int adc_chan = chan->channel; + int ret = 0; + + if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel)) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + mutex_lock(&tsc->mlock); + + switch (chan->channel) { + case 0: + *val = tsc2007_xfer(tsc, READ_X); + break; + case 1: + *val = tsc2007_xfer(tsc, READ_Y); + break; + case 2: + *val = tsc2007_xfer(tsc, READ_Z1); + break; + case 3: + *val = tsc2007_xfer(tsc, READ_Z2); + break; + case 4: + *val = tsc2007_xfer(tsc, (ADC_ON_12BIT | TSC2007_MEASURE_AUX)); + break; + case 5: { + struct ts_event tc; + + tc.x = tsc2007_xfer(tsc, READ_X); + tc.z1 = tsc2007_xfer(tsc, READ_Z1); + tc.z2 = tsc2007_xfer(tsc, READ_Z2); + *val = tsc2007_calculate_resistance(tsc, &tc); + break; + } + case 6: + *val = tsc2007_is_pen_down(tsc); + break; + case 7: + *val = tsc2007_xfer(tsc, + (ADC_ON_12BIT | TSC2007_MEASURE_TEMP0)); + break; + case 8: + *val = tsc2007_xfer(tsc, + (ADC_ON_12BIT | TSC2007_MEASURE_TEMP1)); + break; + } + + /* Prepare for next touch reading - power down ADC, enable PENIRQ */ + tsc2007_xfer(tsc, PWRDOWN); + + mutex_unlock(&tsc->mlock); + + ret = IIO_VAL_INT; + + return ret; +} + +static const struct iio_info tsc2007_iio_info = { + .read_raw = tsc2007_read_raw, + .driver_module = THIS_MODULE, +}; + +int tsc2007_iio_configure(struct tsc2007 *ts) +{ + struct iio_dev *indio_dev; + struct tsc2007_iio *iio; + int error; + + indio_dev = devm_iio_device_alloc(&ts->client->dev, sizeof(*iio)); + if (!indio_dev) { + dev_err(&ts->client->dev, "iio_device_alloc failed\n"); + return -ENOMEM; + } + + iio = iio_priv(indio_dev); + iio->ts = ts; + + indio_dev->name = "tsc2007"; + indio_dev->dev.parent = &ts->client->dev; + indio_dev->info = &tsc2007_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = tsc2007_iio_channel; + indio_dev->num_channels = ARRAY_SIZE(tsc2007_iio_channel); + + error = devm_iio_device_register(&ts->client->dev, indio_dev); + if (error) { + dev_err(&ts->client->dev, + "iio_device_register() failed: %d\n", error); + return error; + } + + return 0; +} |