Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 18 Dec 2016 00:45:00 +0000 (16:45 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 18 Dec 2016 00:45:00 +0000 (16:45 -0800)
Pull input subsystem updates from Dmitry Torokhov:

 - updated support for Synaptics RMI4 devices, including support for
   SMBus controllers, firmware update support, sensor tuning, and PS/2
   guest support

 - ALPS driver now supports tracksticks on SS5 controllers

 - i8042 now uses chassis info to skip selftest on Asus laptops as list
   of individual models became too unwieldy

 - miscellaneous fixes to other drivers

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (67 commits)
  Input: imx6ul_tsc - generalize the averaging property
  Input: drv260x - use generic device properties
  Input: drv260x - use temporary for &client->dev
  Input: drv260x - fix input device's parent assignment
  Input: synaptics-rmi4 - add support for F34 V7 bootloader
  Input: drv260x - fix initializing overdrive voltage
  Input: ALPS - fix protcol -> protocol
  Input: i8042 - comment #else/#endif of CONFIG_PNP
  Input: lpc32xx-keys - fix invalid error handling of a requested irq
  Input: synaptics-rmi4 - fix debug for sensor clip
  Input: synaptics-rmi4 - store the attn data in the driver
  Input: synaptics-rmi4 - allow to add attention data
  Input: synaptics-rmi4 - f03 - grab data passed by transport device
  Input: synaptics-rmi4 - add support for F03
  Input: imx6ul_tsc - convert int to u32
  Input: imx6ul_tsc - add mask when set REG_ADC_CFG
  Input: synaptics-rmi4 - have only one struct platform data
  Input: synaptics-rmi4 - remove EXPORT_SYMBOL_GPL for internal functions
  Input: synaptics-rmi4 - remove mutex calls while updating the firmware
  Input: drv2667 - fix misuse of regmap_update_bits
  ...

51 files changed:
Documentation/devicetree/bindings/input/da9062-onkey.txt
Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
drivers/input/joystick/xpad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/lpc32xx-keys.c
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/keyboard/tca8418_keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/bma150.c
drivers/input/misc/da9063_onkey.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/input/misc/soc_button_array.c
drivers/input/mouse/alps.c
drivers/input/mouse/alps.h
drivers/input/mouse/elan_i2c_core.c
drivers/input/rmi4/Kconfig
drivers/input/rmi4/Makefile
drivers/input/rmi4/rmi_2d_sensor.c
drivers/input/rmi4/rmi_2d_sensor.h
drivers/input/rmi4/rmi_bus.c
drivers/input/rmi4/rmi_bus.h
drivers/input/rmi4/rmi_driver.c
drivers/input/rmi4/rmi_driver.h
drivers/input/rmi4/rmi_f01.c
drivers/input/rmi4/rmi_f03.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f11.c
drivers/input/rmi4/rmi_f12.c
drivers/input/rmi4/rmi_f30.c
drivers/input/rmi4/rmi_f34.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f34.h [new file with mode: 0644]
drivers/input/rmi4/rmi_f34v7.c [new file with mode: 0644]
drivers/input/rmi4/rmi_f54.c
drivers/input/rmi4/rmi_f55.c [new file with mode: 0644]
drivers/input/rmi4/rmi_i2c.c
drivers/input/rmi4/rmi_smbus.c [new file with mode: 0644]
drivers/input/rmi4/rmi_spi.c
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/touchscreen/fsl-imx25-tcq.c
drivers/input/touchscreen/imx6ul_tsc.c
drivers/input/touchscreen/melfas_mip4.c
drivers/input/touchscreen/raydium_i2c_ts.c
drivers/input/touchscreen/silead.c
include/linux/gpio_keys.h
include/linux/platform_data/drv260x-pdata.h [deleted file]
include/linux/rmi.h

index ab0e0488fe928ffe618fc69a10870ec291ed5b84..5f9fbc68e58a45bd95af3ea2a5998d581a328b52 100644 (file)
@@ -1,32 +1,47 @@
-* Dialog DA9062/63 OnKey Module
+* Dialog DA9061/62/63 OnKey Module
 
-This module is part of the DA9062/DA9063. For more details about entire
-chips see Documentation/devicetree/bindings/mfd/da9062.txt and
-Documentation/devicetree/bindings/mfd/da9063.txt
+This module is part of the DA9061/DA9062/DA9063. For more details about entire
+DA9062 and DA9061 chips see Documentation/devicetree/bindings/mfd/da9062.txt
+For DA9063 see Documentation/devicetree/bindings/mfd/da9063.txt
 
-This module provides KEY_POWER, KEY_SLEEP and events.
+This module provides the KEY_POWER event.
 
 Required properties:
 
-- compatible: should be one of:
-       dlg,da9062-onkey
-       dlg,da9063-onkey
+- compatible: should be one of the following valid compatible string lines:
+       "dlg,da9061-onkey", "dlg,da9062-onkey"
+       "dlg,da9062-onkey"
+       "dlg,da9063-onkey"
 
 Optional properties:
 
-  - dlg,disable-key-power : Disable power-down using a long key-press. If this
+- dlg,disable-key-power : Disable power-down using a long key-press. If this
     entry exists the OnKey driver will remove support for the KEY_POWER key
-    press. If this entry does not exist then by default the key-press
-    triggered power down is enabled and the OnKey will support both KEY_POWER
-    and KEY_SLEEP.
+    press when triggered using a long press of the OnKey.
 
-Example:
-
-       pmic0: da9062@58 {
+Example: DA9063
 
+       pmic0: da9063@58 {
                onkey {
                        compatible = "dlg,da9063-onkey";
                        dlg,disable-key-power;
                };
+       };
+
+Example: DA9062
+
+       pmic0: da9062@58 {
+               onkey {
+                       compatible = "dlg,da9062-onkey";
+                       dlg,disable-key-power;
+               };
+       };
+
+Example: DA9061 using a fall-back compatible for the DA9062 onkey driver
 
+       pmic0: da9061@58 {
+               onkey {
+                       compatible = "dlg,da9061-onkey", "dlg,da9062-onkey";
+                       dlg,disable-key-power;
+               };
        };
index 853dff96dd9f7650f6d6b9787266d001a9ded047..d4927c202aef271554022e5fd84451f1febe9212 100644 (file)
@@ -17,6 +17,8 @@ Optional properties:
   This value depends on the touch screen.
 - pre-charge-time: the touch screen need some time to precharge.
   This value depends on the touch screen.
+- touchscreen-average-samples: Number of data samples which are averaged for
+  each read. Valid values are 1, 4, 8, 16 and 32.
 
 Example:
        tsc: tsc@02040000 {
@@ -32,5 +34,6 @@ Example:
                xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
                measure-delay-time = <0xfff>;
                pre-charge-time = <0xffff>;
+               touchscreen-average-samples = <32>;
                status = "okay";
        };
index 820fee4b77b601e7f4c5521e854a06d2dd78408b..ce85ee508238f27514172ecf9559e04a8710f908 100644 (file)
@@ -18,6 +18,8 @@ Optional properties:
 - touchscreen-inverted-y  : See touchscreen.txt
 - touchscreen-swapped-x-y : See touchscreen.txt
 - silead,max-fingers     : maximum number of fingers the touchscreen can detect
+- vddio-supply           : regulator phandle for controller VDDIO
+- avdd-supply            : regulator phandle for controller AVDD
 
 Example:
 
index bccaa4e7304530b559c411afc2fab9cbccd068b3..537643e86f6186dc3189bb15213ba70ad1b8b336 100644 (file)
@@ -14,6 +14,9 @@ Optional properties for Touchscreens:
  - touchscreen-fuzz-pressure   : pressure noise value of the absolute input
                                  device (arbitrary range dependent on the
                                  controller)
+ - touchscreen-average-samples : Number of data samples which are averaged
+                                 for each read (valid values dependent on the
+                                 controller)
  - touchscreen-inverted-x      : X axis is inverted (boolean)
  - touchscreen-inverted-y      : Y axis is inverted (boolean)
  - touchscreen-swapped-x-y     : X and Y axis are swapped (boolean)
index 83af17ad0f1f131d6d397e3df2e15521d0c24b55..6d949965867190458abaa653636ed4ab6702a4aa 100644 (file)
@@ -134,6 +134,7 @@ static const struct xpad_device {
        { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
        { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE },
+       { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE },
        { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
        { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
@@ -1044,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
                packet->data[7] = 0x00;
                packet->data[8] = strong / 512; /* left actuator */
                packet->data[9] = weak / 512;   /* right actuator */
-               packet->data[10] = 0xFF;
-               packet->data[11] = 0x00;
-               packet->data[12] = 0x00;
+               packet->data[10] = 0xFF; /* on period */
+               packet->data[11] = 0x00; /* off period */
+               packet->data[12] = 0xFF; /* repeat count */
                packet->len = 13;
                packet->pending = true;
                break;
index 29093657f2ef8233c667aace8406790a7d859f1d..582462d0af758566a3611b3b7bac7328b6d491a0 100644 (file)
 #include <linux/gpio_keys.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/spinlock.h>
 
 struct gpio_button_data {
        const struct gpio_keys_button *button;
        struct input_dev *input;
+       struct gpio_desc *gpiod;
 
        struct timer_list release_timer;
        unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
@@ -140,7 +140,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
                 */
                disable_irq(bdata->irq);
 
-               if (gpio_is_valid(bdata->button->gpio))
+               if (bdata->gpiod)
                        cancel_delayed_work_sync(&bdata->work);
                else
                        del_timer_sync(&bdata->release_timer);
@@ -358,19 +358,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
        const struct gpio_keys_button *button = bdata->button;
        struct input_dev *input = bdata->input;
        unsigned int type = button->type ?: EV_KEY;
-       int state = gpio_get_value_cansleep(button->gpio);
+       int state;
 
+       state = gpiod_get_value_cansleep(bdata->gpiod);
        if (state < 0) {
-               dev_err(input->dev.parent, "failed to get gpio state\n");
+               dev_err(input->dev.parent,
+                       "failed to get gpio state: %d\n", state);
                return;
        }
 
-       state = (state ? 1 : 0) ^ button->active_low;
        if (type == EV_ABS) {
                if (state)
                        input_event(input, type, button->code, button->value);
        } else {
-               input_event(input, type, button->code, !!state);
+               input_event(input, type, button->code, state);
        }
        input_sync(input);
 }
@@ -456,7 +457,7 @@ static void gpio_keys_quiesce_key(void *data)
 {
        struct gpio_button_data *bdata = data;
 
-       if (gpio_is_valid(bdata->button->gpio))
+       if (bdata->gpiod)
                cancel_delayed_work_sync(&bdata->work);
        else
                del_timer_sync(&bdata->release_timer);
@@ -465,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data)
 static int gpio_keys_setup_key(struct platform_device *pdev,
                                struct input_dev *input,
                                struct gpio_button_data *bdata,
-                               const struct gpio_keys_button *button)
+                               const struct gpio_keys_button *button,
+                               struct fwnode_handle *child)
 {
        const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
@@ -478,18 +480,56 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        bdata->button = button;
        spin_lock_init(&bdata->lock);
 
-       if (gpio_is_valid(button->gpio)) {
+       if (child) {
+               bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child);
+               if (IS_ERR(bdata->gpiod)) {
+                       error = PTR_ERR(bdata->gpiod);
+                       if (error == -ENOENT) {
+                               /*
+                                * GPIO is optional, we may be dealing with
+                                * purely interrupt-driven setup.
+                                */
+                               bdata->gpiod = NULL;
+                       } else {
+                               if (error != -EPROBE_DEFER)
+                                       dev_err(dev, "failed to get gpio: %d\n",
+                                               error);
+                               return error;
+                       }
+               } else {
+                       error = gpiod_direction_input(bdata->gpiod);
+                       if (error) {
+                               dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+                                       desc_to_gpio(bdata->gpiod), error);
+                               return error;
+                       }
+               }
+       } else if (gpio_is_valid(button->gpio)) {
+               /*
+                * Legacy GPIO number, so request the GPIO here and
+                * convert it to descriptor.
+                */
+               unsigned flags = GPIOF_IN;
+
+               if (button->active_low)
+                       flags |= GPIOF_ACTIVE_LOW;
 
-               error = devm_gpio_request_one(&pdev->dev, button->gpio,
-                                             GPIOF_IN, desc);
+               error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
+                                             desc);
                if (error < 0) {
                        dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                button->gpio, error);
                        return error;
                }
 
+               bdata->gpiod = gpio_to_desc(button->gpio);
+               if (!bdata->gpiod)
+                       return -EINVAL;
+       }
+
+       if (bdata->gpiod) {
                if (button->debounce_interval) {
-                       error = gpio_set_debounce(button->gpio,
+                       error = gpiod_set_debounce(bdata->gpiod,
                                        button->debounce_interval * 1000);
                        /* use timer if gpiolib doesn't provide debounce */
                        if (error < 0)
@@ -500,7 +540,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                if (button->irq) {
                        bdata->irq = button->irq;
                } else {
-                       irq = gpio_to_irq(button->gpio);
+                       irq = gpiod_to_irq(bdata->gpiod);
                        if (irq < 0) {
                                error = irq;
                                dev_err(dev,
@@ -518,9 +558,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 
        } else {
                if (!button->irq) {
-                       dev_err(dev, "No IRQ specified\n");
+                       dev_err(dev, "Found button without gpio or irq\n");
                        return -EINVAL;
                }
+
                bdata->irq = button->irq;
 
                if (button->type && button->type != EV_KEY) {
@@ -575,7 +616,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
 
        for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
-               if (gpio_is_valid(bdata->button->gpio))
+               if (bdata->gpiod)
                        gpio_keys_gpio_report_event(bdata);
        }
        input_sync(input);
@@ -612,25 +653,18 @@ static void gpio_keys_close(struct input_dev *input)
  * Handlers for alternative sources of platform_data
  */
 
-#ifdef CONFIG_OF
 /*
- * Translate OpenFirmware node properties into platform_data
+ * Translate properties into platform_data
  */
 static struct gpio_keys_platform_data *
 gpio_keys_get_devtree_pdata(struct device *dev)
 {
-       struct device_node *node, *pp;
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
-       int error;
+       struct fwnode_handle *child;
        int nbuttons;
-       int i;
 
-       node = dev->of_node;
-       if (!node)
-               return ERR_PTR(-ENODEV);
-
-       nbuttons = of_get_available_child_count(node);
+       nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
                return ERR_PTR(-ENODEV);
 
@@ -640,64 +674,47 @@ gpio_keys_get_devtree_pdata(struct device *dev)
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
-       pdata->nbuttons = nbuttons;
-
-       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
-
-       of_property_read_string(node, "label", &pdata->name);
-
-       i = 0;
-       for_each_available_child_of_node(node, pp) {
-               enum of_gpio_flags flags;
+       button = (struct gpio_keys_button *)(pdata + 1);
 
-               button = &pdata->buttons[i++];
+       pdata->buttons = button;
+       pdata->nbuttons = nbuttons;
 
-               button->gpio = of_get_gpio_flags(pp, 0, &flags);
-               if (button->gpio < 0) {
-                       error = button->gpio;
-                       if (error != -ENOENT) {
-                               if (error != -EPROBE_DEFER)
-                                       dev_err(dev,
-                                               "Failed to get gpio flags, error: %d\n",
-                                               error);
-                               return ERR_PTR(error);
-                       }
-               } else {
-                       button->active_low = flags & OF_GPIO_ACTIVE_LOW;
-               }
+       pdata->rep = device_property_read_bool(dev, "autorepeat");
 
-               button->irq = irq_of_parse_and_map(pp, 0);
+       device_property_read_string(dev, "label", &pdata->name);
 
-               if (!gpio_is_valid(button->gpio) && !button->irq) {
-                       dev_err(dev, "Found button without gpios or irqs\n");
-                       return ERR_PTR(-EINVAL);
-               }
+       device_for_each_child_node(dev, child) {
+               if (is_of_node(child))
+                       button->irq =
+                               irq_of_parse_and_map(to_of_node(child), 0);
 
-               if (of_property_read_u32(pp, "linux,code", &button->code)) {
-                       dev_err(dev, "Button without keycode: 0x%x\n",
-                               button->gpio);
+               if (fwnode_property_read_u32(child, "linux,code",
+                                            &button->code)) {
+                       dev_err(dev, "Button without keycode\n");
+                       fwnode_handle_put(child);
                        return ERR_PTR(-EINVAL);
                }
 
-               button->desc = of_get_property(pp, "label", NULL);
+               fwnode_property_read_string(child, "label", &button->desc);
 
-               if (of_property_read_u32(pp, "linux,input-type", &button->type))
+               if (fwnode_property_read_u32(child, "linux,input-type",
+                                            &button->type))
                        button->type = EV_KEY;
 
-               button->wakeup = of_property_read_bool(pp, "wakeup-source") ||
-                                /* legacy name */
-                                of_property_read_bool(pp, "gpio-key,wakeup");
+               button->wakeup =
+                       fwnode_property_read_bool(child, "wakeup-source") ||
+                       /* legacy name */
+                       fwnode_property_read_bool(child, "gpio-key,wakeup");
 
-               button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+               button->can_disable =
+                       fwnode_property_read_bool(child, "linux,can-disable");
 
-               if (of_property_read_u32(pp, "debounce-interval",
+               if (fwnode_property_read_u32(child, "debounce-interval",
                                         &button->debounce_interval))
                        button->debounce_interval = 5;
-       }
 
-       if (pdata->nbuttons == 0)
-               return ERR_PTR(-EINVAL);
+               button++;
+       }
 
        return pdata;
 }
@@ -708,20 +725,11 @@ static const struct of_device_id gpio_keys_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
 
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_get_devtree_pdata(struct device *dev)
-{
-       return ERR_PTR(-ENODEV);
-}
-
-#endif
-
 static int gpio_keys_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+       struct fwnode_handle *child = NULL;
        struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
        size_t size;
@@ -774,14 +782,28 @@ static int gpio_keys_probe(struct platform_device *pdev)
                const struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_button_data *bdata = &ddata->data[i];
 
-               error = gpio_keys_setup_key(pdev, input, bdata, button);
-               if (error)
+               if (!dev_get_platdata(dev)) {
+                       child = device_get_next_child_node(&pdev->dev, child);
+                       if (!child) {
+                               dev_err(&pdev->dev,
+                                       "missing child device node for entry %d\n",
+                                       i);
+                               return -EINVAL;
+                       }
+               }
+
+               error = gpio_keys_setup_key(pdev, input, bdata, button, child);
+               if (error) {
+                       fwnode_handle_put(child);
                        return error;
+               }
 
                if (button->wakeup)
                        wakeup = 1;
        }
 
+       fwnode_handle_put(child);
+
        error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
        if (error) {
                dev_err(dev, "Unable to export keys/switches, error: %d\n",
@@ -814,8 +836,7 @@ static int gpio_keys_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int gpio_keys_suspend(struct device *dev)
+static int __maybe_unused gpio_keys_suspend(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        struct input_dev *input = ddata->input;
@@ -837,7 +858,7 @@ static int gpio_keys_suspend(struct device *dev)
        return 0;
 }
 
-static int gpio_keys_resume(struct device *dev)
+static int __maybe_unused gpio_keys_resume(struct device *dev)
 {
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        struct input_dev *input = ddata->input;
@@ -863,7 +884,6 @@ static int gpio_keys_resume(struct device *dev)
        gpio_keys_report_state(ddata);
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);
 
@@ -873,7 +893,7 @@ static struct platform_driver gpio_keys_device_driver = {
        .driver         = {
                .name   = "gpio-keys",
                .pm     = &gpio_keys_pm_ops,
-               .of_match_table = of_match_ptr(gpio_keys_of_match),
+               .of_match_table = gpio_keys_of_match,
        }
 };
 
index 62bdb1d48c49dbd990ce37f2da335ee8d60b472d..bed4f2086158e3073b325dcc75fbcac3c51df4da 100644 (file)
 #define DRV_NAME       "gpio-keys-polled"
 
 struct gpio_keys_button_data {
+       struct gpio_desc *gpiod;
        int last_state;
        int count;
        int threshold;
-       int can_sleep;
 };
 
 struct gpio_keys_polled_dev {
@@ -46,7 +46,7 @@ struct gpio_keys_polled_dev {
 };
 
 static void gpio_keys_button_event(struct input_polled_dev *dev,
-                                  struct gpio_keys_button *button,
+                                  const struct gpio_keys_button *button,
                                   int state)
 {
        struct gpio_keys_polled_dev *bdev = dev->private;
@@ -70,21 +70,22 @@ static void gpio_keys_button_event(struct input_polled_dev *dev,
 }
 
 static void gpio_keys_polled_check_state(struct input_polled_dev *dev,
-                                        struct gpio_keys_button *button,
+                                        const struct gpio_keys_button *button,
                                         struct gpio_keys_button_data *bdata)
 {
        int state;
 
-       if (bdata->can_sleep)
-               state = !!gpiod_get_value_cansleep(button->gpiod);
-       else
-               state = !!gpiod_get_value(button->gpiod);
-
-       gpio_keys_button_event(dev, button, state);
+       state = gpiod_get_value_cansleep(bdata->gpiod);
+       if (state < 0) {
+               dev_err(dev->input->dev.parent,
+                       "failed to get gpio state: %d\n", state);
+       } else {
+               gpio_keys_button_event(dev, button, state);
 
-       if (state != bdata->last_state) {
-               bdata->count = 0;
-               bdata->last_state = state;
+               if (state != bdata->last_state) {
+                       bdata->count = 0;
+                       bdata->last_state = state;
+               }
        }
 }
 
@@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
                pdata->disable(bdev->dev);
 }
 
-static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
+static struct gpio_keys_platform_data *
+gpio_keys_polled_get_devtree_pdata(struct device *dev)
 {
        struct gpio_keys_platform_data *pdata;
        struct gpio_keys_button *button;
        struct fwnode_handle *child;
-       int error;
        int nbuttons;
 
        nbuttons = device_get_child_node_count(dev);
        if (nbuttons == 0)
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button),
                             GFP_KERNEL);
        if (!pdata)
                return ERR_PTR(-ENOMEM);
 
-       pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
+       button = (struct gpio_keys_button *)(pdata + 1);
+
+       pdata->buttons = button;
+       pdata->nbuttons = nbuttons;
 
        pdata->rep = device_property_present(dev, "autorepeat");
        device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
 
        device_for_each_child_node(dev, child) {
-               struct gpio_desc *desc;
-
-               desc = devm_get_gpiod_from_child(dev, NULL, child);
-               if (IS_ERR(desc)) {
-                       error = PTR_ERR(desc);
-                       if (error != -EPROBE_DEFER)
-                               dev_err(dev,
-                                       "Failed to get gpio flags, error: %d\n",
-                                       error);
-                       fwnode_handle_put(child);
-                       return ERR_PTR(error);
-               }
-
-               button = &pdata->buttons[pdata->nbuttons++];
-               button->gpiod = desc;
-
-               if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
-                       dev_err(dev, "Button without keycode: %d\n",
-                               pdata->nbuttons - 1);
+               if (fwnode_property_read_u32(child, "linux,code",
+                                            &button->code)) {
+                       dev_err(dev, "button without keycode\n");
                        fwnode_handle_put(child);
                        return ERR_PTR(-EINVAL);
                }
@@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                if (fwnode_property_read_u32(child, "debounce-interval",
                                             &button->debounce_interval))
                        button->debounce_interval = 5;
-       }
 
-       if (pdata->nbuttons == 0)
-               return ERR_PTR(-EINVAL);
+               button++;
+       }
 
        return pdata;
 }
@@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
        int i, min = 0, max = 0;
 
        for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_keys_button *button = &pdata->buttons[i];
+               const struct gpio_keys_button *button = &pdata->buttons[i];
 
                if (button->type != EV_ABS || button->code != code)
                        continue;
@@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input,
                if (button->value > max)
                        max = button->value;
        }
+
        input_set_abs_params(input, code, min, max, 0, 0);
 }
 
@@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
 static int gpio_keys_polled_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct fwnode_handle *child = NULL;
        const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
        struct gpio_keys_polled_dev *bdev;
        struct input_polled_dev *poll_dev;
@@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                pdata = gpio_keys_polled_get_devtree_pdata(dev);
                if (IS_ERR(pdata))
                        return PTR_ERR(pdata);
-               if (!pdata) {
-                       dev_err(dev, "missing platform data\n");
-                       return -EINVAL;
-               }
        }
 
        if (!pdata->poll_interval) {
@@ -300,20 +285,48 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                __set_bit(EV_REP, input->evbit);
 
        for (i = 0; i < pdata->nbuttons; i++) {
-               struct gpio_keys_button *button = &pdata->buttons[i];
+               const struct gpio_keys_button *button = &pdata->buttons[i];
                struct gpio_keys_button_data *bdata = &bdev->data[i];
                unsigned int type = button->type ?: EV_KEY;
 
                if (button->wakeup) {
                        dev_err(dev, DRV_NAME " does not support wakeup\n");
+                       fwnode_handle_put(child);
                        return -EINVAL;
                }
 
-               /*
-                * Legacy GPIO number so request the GPIO here and
-                * convert it to descriptor.
-                */
-               if (!button->gpiod && gpio_is_valid(button->gpio)) {
+               if (!dev_get_platdata(dev)) {
+                       /* No legacy static platform data */
+                       child = device_get_next_child_node(dev, child);
+                       if (!child) {
+                               dev_err(dev, "missing child device node\n");
+                               return -EINVAL;
+                       }
+
+                       bdata->gpiod = devm_get_gpiod_from_child(dev, NULL,
+                                                                child);
+                       if (IS_ERR(bdata->gpiod)) {
+                               error = PTR_ERR(bdata->gpiod);
+                               if (error != -EPROBE_DEFER)
+                                       dev_err(dev,
+                                               "failed to get gpio: %d\n",
+                                               error);
+                               fwnode_handle_put(child);
+                               return error;
+                       }
+
+                       error = gpiod_direction_input(bdata->gpiod);
+                       if (error) {
+                               dev_err(dev, "Failed to configure GPIO %d as input: %d\n",
+                                       desc_to_gpio(bdata->gpiod), error);
+                               fwnode_handle_put(child);
+                               return error;
+                       }
+               } else if (gpio_is_valid(button->gpio)) {
+                       /*
+                        * Legacy GPIO number so request the GPIO here and
+                        * convert it to descriptor.
+                        */
                        unsigned flags = GPIOF_IN;
 
                        if (button->active_low)
@@ -322,18 +335,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                        error = devm_gpio_request_one(&pdev->dev, button->gpio,
                                        flags, button->desc ? : DRV_NAME);
                        if (error) {
-                               dev_err(dev, "unable to claim gpio %u, err=%d\n",
+                               dev_err(dev,
+                                       "unable to claim gpio %u, err=%d\n",
                                        button->gpio, error);
                                return error;
                        }
 
-                       button->gpiod = gpio_to_desc(button->gpio);
+                       bdata->gpiod = gpio_to_desc(button->gpio);
+                       if (!bdata->gpiod) {
+                               dev_err(dev,
+                                       "unable to convert gpio %u to descriptor\n",
+                                       button->gpio);
+                               return -EINVAL;
+                       }
                }
 
-               if (IS_ERR(button->gpiod))
-                       return PTR_ERR(button->gpiod);
-
-               bdata->can_sleep = gpiod_cansleep(button->gpiod);
                bdata->last_state = -1;
                bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
                                                pdata->poll_interval);
@@ -344,6 +360,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                                                        button->code);
        }
 
+       fwnode_handle_put(child);
+
        bdev->poll_dev = poll_dev;
        bdev->dev = dev;
        bdev->pdata = pdata;
index 265d641c40e205767d96fbe81b7f794d32a0dc06..632523d4f5dc11b21e1591ccd79f841dbb640194 100644 (file)
@@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev)
        }
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0 || irq >= NR_IRQS) {
+       if (irq < 0) {
                dev_err(&pdev->dev, "failed to get platform irq\n");
                return -EINVAL;
        }
index fcef5d1365e2a3034e3a9544f7e403a0680a5058..e24443376e756fe6290cfba7e5dbb0aa5f336b9f 100644 (file)
@@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
        error = of_property_read_u32(np, "marvell,debounce-interval",
                                     &pdata->debounce_interval);
        if (error) {
-               dev_err(dev, "failed to parse debpunce-interval\n");
+               dev_err(dev, "failed to parse debounce-interval\n");
                return error;
        }
 
index 9002298698fce303de6a61b0253c6b0a667b4818..3048ef3e3e1639e2f7d24b9e60c6cf45cfe01c8a 100644 (file)
@@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
        int error, col, row;
        u8 reg, state, code;
 
-       /* Initial read of the key event FIFO */
-       error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+       do {
+               error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
+               if (error < 0) {
+                       dev_err(&keypad_data->client->dev,
+                               "unable to read REG_KEY_EVENT_A\n");
+                       break;
+               }
+
+               /* Assume that key code 0 signifies empty FIFO */
+               if (reg <= 0)
+                       break;
 
-       /* Assume that key code 0 signifies empty FIFO */
-       while (error >= 0 && reg > 0) {
                state = reg & KEY_EVENT_VALUE;
                code  = reg & KEY_EVENT_CODE;
 
@@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data)
 
                /* Read for next loop */
                error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, &reg);
-       }
-
-       if (error < 0)
-               dev_err(&keypad_data->client->dev,
-                       "unable to read REG_KEY_EVENT_A\n");
+       } while (1);
 
        input_sync(input);
 }
index 7ffb614ce5664cd7955600a216b121e7c61a1fe2..1ae4d9617ff807c71ac011f79413d6faeed2d202 100644 (file)
@@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY
          will be called da9055_onkey.
 
 config INPUT_DA9063_ONKEY
-       tristate "Dialog DA9062/63 OnKey"
+       tristate "Dialog DA9063/62/61 OnKey"
        depends on MFD_DA9063 || MFD_DA9062
        help
-         Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs
-         as an input device capable of reporting the power button status.
+         Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power
+         Management ICs as an input device capable of reporting the
+         power button status.
 
          To compile this driver as a module, choose M here: the module
          will be called da9063_onkey.
index b0d445390ee44dfe3fb2bf3fea11d0d8f9257a62..2124390ec38c606bf55ba0d953f681862d9c962f 100644 (file)
@@ -538,8 +538,13 @@ 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 && chip_id != BMA180_CHIP_ID) {
+       if (chip_id != BMA150_CHIP_ID &&
+           (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) {
                dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id);
                return -EINVAL;
        }
@@ -643,7 +648,9 @@ 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 },
        { }
index bb863e062b03b3cf66317c8899401478e2f06930..b4ff1e86d3d30fee8a4e3ff4e33dd066c6a869b0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * OnKey device driver for DA9063 and DA9062 PMICs
+ * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
  * Copyright (C) 2015  Dialog Semiconductor Ltd.
  *
  * This program is free software; you can redistribute it and/or
@@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = {
        { .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
        { },
 };
+MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
 
 static void da9063_poll_on(struct work_struct *work)
 {
@@ -149,13 +150,13 @@ static void da9063_poll_on(struct work_struct *work)
                         * and then send shutdown command
                         */
                        dev_dbg(&onkey->input->dev,
-                               "Sending SHUTDOWN to DA9063 ...\n");
+                               "Sending SHUTDOWN to PMIC ...\n");
                        error = regmap_write(onkey->regmap,
                                             config->onkey_shutdown,
                                             config->onkey_shutdown_mask);
                        if (error)
                                dev_err(&onkey->input->dev,
-                                       "Cannot SHUTDOWN DA9063: %d\n",
+                                       "Cannot SHUTDOWN PMIC: %d\n",
                                        error);
                }
        }
@@ -300,6 +301,6 @@ static struct platform_driver da9063_onkey_driver = {
 module_platform_driver(da9063_onkey_driver);
 
 MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
-MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062");
+MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
index 2adfd86c869a5364312a2d8df904d2bd7df68b52..0a2b865b100040d99731abe52c1261c5f390f1b3 100644 (file)
@@ -18,8 +18,6 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
-#include <linux/platform_device.h>
 #include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -27,7 +25,6 @@
 #include <linux/regulator/consumer.h>
 
 #include <dt-bindings/input/ti-drv260x.h>
-#include <linux/platform_data/drv260x-pdata.h>
 
 #define DRV260X_STATUS         0x0
 #define DRV260X_MODE           0x1
@@ -468,90 +465,39 @@ static const struct regmap_config drv260x_regmap_config = {
        .cache_type = REGCACHE_NONE,
 };
 
-#ifdef CONFIG_OF
-static int drv260x_parse_dt(struct device *dev,
-                           struct drv260x_data *haptics)
-{
-       struct device_node *np = dev->of_node;
-       unsigned int voltage;
-       int error;
-
-       error = of_property_read_u32(np, "mode", &haptics->mode);
-       if (error) {
-               dev_err(dev, "%s: No entry for mode\n", __func__);
-               return error;
-       }
-
-       error = of_property_read_u32(np, "library-sel", &haptics->library);
-       if (error) {
-               dev_err(dev, "%s: No entry for library selection\n",
-                       __func__);
-               return error;
-       }
-
-       error = of_property_read_u32(np, "vib-rated-mv", &voltage);
-       if (!error)
-               haptics->rated_voltage = drv260x_calculate_voltage(voltage);
-
-
-       error = of_property_read_u32(np, "vib-overdrive-mv", &voltage);
-       if (!error)
-               haptics->overdrive_voltage = drv260x_calculate_voltage(voltage);
-
-       return 0;
-}
-#else
-static inline int drv260x_parse_dt(struct device *dev,
-                                  struct drv260x_data *haptics)
-{
-       dev_err(dev, "no platform data defined\n");
-
-       return -EINVAL;
-}
-#endif
-
 static int drv260x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct device *dev = &client->dev;
        struct drv260x_data *haptics;
+       u32 voltage;
        int error;
 
-       haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL);
+       haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL);
        if (!haptics)
                return -ENOMEM;
 
-       haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT;
-       haptics->rated_voltage = DRV260X_DEF_RATED_VOLT;
-
-       if (pdata) {
-               haptics->mode = pdata->mode;
-               haptics->library = pdata->library_selection;
-               if (pdata->vib_overdrive_voltage)
-                       haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage);
-               if (pdata->vib_rated_voltage)
-                       haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage);
-       } else if (client->dev.of_node) {
-               error = drv260x_parse_dt(&client->dev, haptics);
-               if (error)
-                       return error;
-       } else {
-               dev_err(&client->dev, "Platform data not set\n");
-               return -ENODEV;
+       error = device_property_read_u32(dev, "mode", &haptics->mode);
+       if (error) {
+               dev_err(dev, "Can't fetch 'mode' property: %d\n", error);
+               return error;
        }
 
-
        if (haptics->mode < DRV260X_LRA_MODE ||
            haptics->mode > DRV260X_ERM_MODE) {
-               dev_err(&client->dev,
-                       "Vibrator mode is invalid: %i\n",
-                       haptics->mode);
+               dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode);
                return -EINVAL;
        }
 
+       error = device_property_read_u32(dev, "library-sel", &haptics->library);
+       if (error) {
+               dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error);
+               return error;
+       }
+
        if (haptics->library < DRV260X_LIB_EMPTY ||
            haptics->library > DRV260X_ERM_LIB_F) {
-               dev_err(&client->dev,
+               dev_err(dev,
                        "Library value is invalid: %i\n", haptics->library);
                return -EINVAL;
        }
@@ -559,40 +505,44 @@ static int drv260x_probe(struct i2c_client *client,
        if (haptics->mode == DRV260X_LRA_MODE &&
            haptics->library != DRV260X_LIB_EMPTY &&
            haptics->library != DRV260X_LIB_LRA) {
-               dev_err(&client->dev,
-                       "LRA Mode with ERM Library mismatch\n");
+               dev_err(dev, "LRA Mode with ERM Library mismatch\n");
                return -EINVAL;
        }
 
        if (haptics->mode == DRV260X_ERM_MODE &&
            (haptics->library == DRV260X_LIB_EMPTY ||
             haptics->library == DRV260X_LIB_LRA)) {
-               dev_err(&client->dev,
-                       "ERM Mode with LRA Library mismatch\n");
+               dev_err(dev, "ERM Mode with LRA Library mismatch\n");
                return -EINVAL;
        }
 
-       haptics->regulator = devm_regulator_get(&client->dev, "vbat");
+       error = device_property_read_u32(dev, "vib-rated-mv", &voltage);
+       haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT :
+                                        drv260x_calculate_voltage(voltage);
+
+       error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage);
+       haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT :
+                                            drv260x_calculate_voltage(voltage);
+
+       haptics->regulator = devm_regulator_get(dev, "vbat");
        if (IS_ERR(haptics->regulator)) {
                error = PTR_ERR(haptics->regulator);
-               dev_err(&client->dev,
-                       "unable to get regulator, error: %d\n", error);
+               dev_err(dev, "unable to get regulator, error: %d\n", error);
                return error;
        }
 
-       haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",
+       haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
                                                       GPIOD_OUT_HIGH);
        if (IS_ERR(haptics->enable_gpio))
                return PTR_ERR(haptics->enable_gpio);
 
-       haptics->input_dev = devm_input_allocate_device(&client->dev);
+       haptics->input_dev = devm_input_allocate_device(dev);
        if (!haptics->input_dev) {
                dev_err(&client->dev, "Failed to allocate input device\n");
                return -ENOMEM;
        }
 
        haptics->input_dev->name = "drv260x:haptics";
-       haptics->input_dev->dev.parent = client->dev.parent;
        haptics->input_dev->close = drv260x_close;
        input_set_drvdata(haptics->input_dev, haptics);
        input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
@@ -600,8 +550,7 @@ static int drv260x_probe(struct i2c_client *client,
        error = input_ff_create_memless(haptics->input_dev, NULL,
                                        drv260x_haptics_play);
        if (error) {
-               dev_err(&client->dev, "input_ff_create() failed: %d\n",
-                       error);
+               dev_err(dev, "input_ff_create() failed: %d\n", error);
                return error;
        }
 
@@ -613,21 +562,19 @@ static int drv260x_probe(struct i2c_client *client,
        haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config);
        if (IS_ERR(haptics->regmap)) {
                error = PTR_ERR(haptics->regmap);
-               dev_err(&client->dev, "Failed to allocate register map: %d\n",
-                       error);
+               dev_err(dev, "Failed to allocate register map: %d\n", error);
                return error;
        }
 
        error = drv260x_init(haptics);
        if (error) {
-               dev_err(&client->dev, "Device init failed: %d\n", error);
+               dev_err(dev, "Device init failed: %d\n", error);
                return error;
        }
 
        error = input_register_device(haptics->input_dev);
        if (error) {
-               dev_err(&client->dev, "couldn't register input device: %d\n",
-                       error);
+               dev_err(dev, "couldn't register input device: %d\n", error);
                return error;
        }
 
index ef9bc12b3be3565d816c9890556dedd922c4ae95..dcb6d8e94b11215e07f4d5225b585e21ffd680f0 100644 (file)
@@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input)
 
        cancel_work_sync(&haptics->work);
 
-       error = regmap_update_bits(haptics->regmap,
-                                  DRV2665_CTRL_2, DRV2665_STANDBY, 1);
+       error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+                                  DRV2665_STANDBY, DRV2665_STANDBY);
        if (error)
                dev_err(&haptics->client->dev,
                        "Failed to enter standby mode: %d\n", error);
@@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev)
 
        if (haptics->input_dev->users) {
                ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
-                               DRV2665_STANDBY, 1);
+                                        DRV2665_STANDBY, DRV2665_STANDBY);
                if (ret) {
                        dev_err(dev, "Failed to set standby mode\n");
                        regulator_disable(haptics->regulator);
index d5ba7481328cf289fa8da9a326421ca1da0fa07c..2849bb6906a8f799dae30a022937a47740595a28 100644 (file)
@@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input)
        cancel_work_sync(&haptics->work);
 
        error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
-                               DRV2667_STANDBY, 1);
+                                  DRV2667_STANDBY, DRV2667_STANDBY);
        if (error)
                dev_err(&haptics->client->dev,
                        "Failed to enter standby mode: %d\n", error);
@@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev)
 
        if (haptics->input_dev->users) {
                ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
-                               DRV2667_STANDBY, 1);
+                                        DRV2667_STANDBY, DRV2667_STANDBY);
                if (ret) {
                        dev_err(dev, "Failed to set standby mode\n");
                        regulator_disable(haptics->regulator);
index c14b82709b0f09481c7fc6c8c52c0e384dd33da1..908b51089dee4b1cb128393cba441eecc477c994 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/acpi.h>
 #include <linux/gpio/consumer.h>
 #include <linux/gpio_keys.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 
 /*
@@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev,
                        continue;
 
                gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
-               if (gpio < 0)
+               if (!gpio_is_valid(gpio))
                        continue;
 
                gpio_keys[n_buttons].type = info->event_type;
@@ -166,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev)
 
        button_info = (struct soc_button_info *)id->driver_data;
 
+       if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) {
+               dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n");
+               return -ENODEV;
+       }
+
        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
index 6d7de9bfed9a7f2bdf872474f156613740632539..328edc8c8786339d009abb99fe6e000d9edbb805 100644 (file)
@@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
                alps_process_touchpad_packet_v7(psmouse);
 }
 
-static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
+static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte)
 {
-       unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+       enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE;
 
        switch (byte[3] & 0x30) {
        case 0x00:
-               if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
-                   (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
-                   byte[5] == 0x00) {
+               if (SS4_IS_IDLE_V2(byte)) {
                        pkt_id = SS4_PACKET_ID_IDLE;
                } else {
                        pkt_id = SS4_PACKET_ID_ONE;
@@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
                              unsigned char *p, struct psmouse *psmouse)
 {
        struct alps_data *priv = psmouse->private;
-       unsigned char pkt_id;
+       enum SS4_PACKET_ID pkt_id;
        unsigned int no_data_x, no_data_y;
 
        pkt_id = alps_get_pkt_id_ss4_v2(p);
@@ -1267,18 +1265,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
                break;
 
        case SS4_PACKET_ID_STICK:
-               if (!(priv->flags & ALPS_DUALPOINT)) {
-                       psmouse_warn(psmouse,
-                                    "Rejected trackstick packet from non DualPoint device");
-               } else {
-                       int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
-                       int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
-                       int pressure = (s8)(p[4] & 0x7f);
-
-                       input_report_rel(priv->dev2, REL_X, x);
-                       input_report_rel(priv->dev2, REL_Y, -y);
-                       input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
-               }
+               /*
+                * x, y, and pressure are decoded in
+                * alps_process_packet_ss4_v2()
+                */
+               f->first_mp = 0;
+               f->is_mp = 0;
                break;
 
        case SS4_PACKET_ID_IDLE:
@@ -1346,6 +1338,27 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
 
        priv->multi_packet = 0;
 
+       /* Report trackstick */
+       if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) {
+               if (!(priv->flags & ALPS_DUALPOINT)) {
+                       psmouse_warn(psmouse,
+                                    "Rejected trackstick packet from non DualPoint device");
+                       return;
+               }
+
+               input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet));
+               input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet));
+               input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet));
+
+               input_report_key(dev2, BTN_LEFT, f->ts_left);
+               input_report_key(dev2, BTN_RIGHT, f->ts_right);
+               input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
+
+               input_sync(dev2);
+               return;
+       }
+
+       /* Report touchpad */
        alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
 
        input_mt_report_finger_count(dev, f->fingers);
@@ -1356,13 +1369,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
 
        input_report_abs(dev, ABS_PRESSURE, f->pressure);
        input_sync(dev);
-
-       if (priv->flags & ALPS_DUALPOINT) {
-               input_report_key(dev2, BTN_LEFT, f->ts_left);
-               input_report_key(dev2, BTN_RIGHT, f->ts_right);
-               input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
-               input_sync(dev2);
-       }
 }
 
 static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
index b9417e2d7ad3a7ba01aff4d7c5504a619090b0b5..cde6f4bd8ea2e3f0f70fbccf3f684e5cd079ec04 100644 (file)
@@ -54,7 +54,15 @@ enum SS4_PACKET_ID {
 
 #define SS4_MASK_NORMAL_BUTTONS                0x07
 
-#define SS4_1F_X_V2(_b)                ((_b[0] & 0x0007) |             \
+#define SS4_IS_IDLE_V2(_b)     (((_b[0]) == 0x18) &&           \
+                                ((_b[1]) == 0x10) &&           \
+                                ((_b[2]) == 0x00) &&           \
+                                ((_b[3] & 0x88) == 0x08) &&    \
+                                ((_b[4]) == 0x10) &&           \
+                                ((_b[5]) == 0x00)              \
+                               )
+
+#define SS4_1F_X_V2(_b)                (((_b[0]) & 0x0007) |           \
                                 ((_b[1] << 3) & 0x0078) |      \
                                 ((_b[1] << 2) & 0x0380) |      \
                                 ((_b[2] << 5) & 0x1C00)        \
@@ -101,6 +109,18 @@ enum SS4_PACKET_ID {
 #define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10)
 #define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10)
 
+#define SS4_TS_X_V2(_b)                (s8)(                           \
+                                ((_b[0] & 0x01) << 7) |        \
+                                (_b[1] & 0x7F)         \
+                               )
+
+#define SS4_TS_Y_V2(_b)                (s8)(                           \
+                                ((_b[3] & 0x01) << 7) |        \
+                                (_b[2] & 0x7F)         \
+                               )
+
+#define SS4_TS_Z_V2(_b)                (s8)(_b[4] & 0x7F)
+
 
 #define SS4_MFPACKET_NO_AX     8160    /* X-Coordinate value */
 #define SS4_MFPACKET_NO_AY     4080    /* Y-Coordinate value */
@@ -146,7 +166,7 @@ struct alps_protocol_info {
  *   (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 protcol used by the device.
+ * @protocol_info: information about protocol used by the device.
  *
  * Many (but not all) ALPS touchpads can be identified by looking at the
  * values returned in the "E7 report" and/or the "EC report."  This table
index d15b338130213c53489baa600d6dcea1500790d4..fa598f7f4372c1ed0167b941a57a4b663a5361de 100644 (file)
@@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client,
        if (error)
                return error;
 
+       dev_info(&client->dev,
+                "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n",
+                data->product_id,
+                data->fw_version,
+                data->sm_version,
+                data->iap_version);
+
        dev_dbg(&client->dev,
-               "Elan Touchpad Information:\n"
-               "    Module product ID:  0x%04x\n"
-               "    Firmware Version:  0x%04x\n"
-               "    Sample Version:  0x%04x\n"
-               "    IAP Version:  0x%04x\n"
+               "Elan Touchpad Extra Information:\n"
                "    Max ABS X,Y:   %d,%d\n"
                "    Width X,Y:   %d,%d\n"
                "    Resolution X,Y:   %d,%d (dots/mm)\n",
-               data->product_id,
-               data->fw_version,
-               data->sm_version,
-               data->iap_version,
                data->max_x, data->max_y,
                data->width_x, data->width_y,
                data->x_res, data->y_res);
index 4c8a55857e004aadb1ccfdf43165862c3e5286d5..30cc627a4f4531ff93014ea94bf9835b0b37e8bc 100644 (file)
@@ -27,6 +27,27 @@ config RMI4_SPI
 
          If unsure, say N.
 
+config RMI4_SMB
+       tristate "RMI4 SMB Support"
+       depends on RMI4_CORE && I2C
+       help
+         Say Y here if you want to support RMI4 devices connected to an SMB
+         bus.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the module will be
+         called rmi_smbus.
+
+config RMI4_F03
+        bool "RMI4 Function 03 (PS2 Guest)"
+        depends on RMI4_CORE && SERIO
+        help
+          Say Y here if you want to add support for RMI4 function 03.
+
+          Function 03 provides PS2 guest support for RMI4 devices. This
+          includes support for TrackPoints on TouchPads.
+
 config RMI4_2D_SENSOR
        bool
        depends on RMI4_CORE
@@ -62,13 +83,34 @@ config RMI4_F30
          Function 30 provides GPIO and LED support for RMI4 devices. This
          includes support for buttons on TouchPads and ClickPads.
 
+config RMI4_F34
+       bool "RMI4 Function 34 (Device reflash)"
+       depends on RMI4_CORE
+       select FW_LOADER
+       help
+         Say Y here if you want to add support for RMI4 function 34.
+
+         Function 34 provides support for upgrading the firmware on the RMI4
+         device via the firmware loader interface. This is triggered using a
+         sysfs attribute.
+
 config RMI4_F54
        bool "RMI4 Function 54 (Analog diagnostics)"
        depends on RMI4_CORE
        depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
        select VIDEOBUF2_VMALLOC
+       select RMI4_F55
        help
          Say Y here if you want to add support for RMI4 function 54
 
          Function 54 provides access to various diagnostic features in certain
          RMI4 touch sensors.
+
+config RMI4_F55
+       bool "RMI4 Function 55 (Sensor tuning)"
+       depends on RMI4_CORE
+       help
+         Say Y here if you want to add support for RMI4 function 55
+
+         Function 55 provides access to the RMI4 touch sensor tuning
+         mechanism.
index 0bafc8502c4b98b5e8a5629470592b7b7400b6f0..9aaac3dd8613d66176c7ca7c01873184bd9013b5 100644 (file)
@@ -4,11 +4,15 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
 rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
 
 # Function drivers
+rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
 rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
 rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
 rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
+rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
 rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
+rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
 
 # Transports
 obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
 obj-$(CONFIG_RMI4_SPI) += rmi_spi.o
+obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o
index e97bd7fabccc5ec3b483070b3d58a55cca12b1f2..07007ff8e29fff7bf0d245a0174b17e8fcbccf29 100644 (file)
@@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
                                sensor->dmax = DMAX * res_x;
                }
 
-               input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
-               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
-               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
-               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+               input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+               input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+               input_set_abs_params(input, ABS_MT_TOOL_TYPE,
+                                    0, MT_TOOL_MAX, 0, 0);
 
                if (sensor->sensor_type == rmi_sensor_touchpad)
                        input_flags = INPUT_MT_POINTER;
index 77fcdfef003c6f96f19a796ffa410ba9b2026f82..c871bef4dac098f3af9c57bdd132a99e0758a72b 100644 (file)
@@ -67,6 +67,8 @@ struct rmi_2d_sensor {
        u8 report_rel;
        u8 x_mm;
        u8 y_mm;
+       enum rmi_reg_state dribble;
+       enum rmi_reg_state palm_detect;
 };
 
 int rmi_2d_sensor_of_probe(struct device *dev,
index ef8c747c35e76f0c77eaf86300f724e30cf6e0ff..1c40d94ca506cceb776798cb8db1444e36824ffc 100644 (file)
@@ -230,6 +230,9 @@ err_put_device:
 
 void rmi_unregister_function(struct rmi_function *fn)
 {
+       rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
+                       fn->fd.function_number);
+
        device_del(&fn->dev);
        of_node_put(fn->dev.of_node);
        put_device(&fn->dev);
@@ -302,6 +305,9 @@ struct bus_type rmi_bus_type = {
 
 static struct rmi_function_handler *fn_handlers[] = {
        &rmi_f01_handler,
+#ifdef CONFIG_RMI4_F03
+       &rmi_f03_handler,
+#endif
 #ifdef CONFIG_RMI4_F11
        &rmi_f11_handler,
 #endif
@@ -311,9 +317,15 @@ static struct rmi_function_handler *fn_handlers[] = {
 #ifdef CONFIG_RMI4_F30
        &rmi_f30_handler,
 #endif
+#ifdef CONFIG_RMI4_F34
+       &rmi_f34_handler,
+#endif
 #ifdef CONFIG_RMI4_F54
        &rmi_f54_handler,
 #endif
+#ifdef CONFIG_RMI4_F55
+       &rmi_f55_handler,
+#endif
 };
 
 static void __rmi_unregister_function_handlers(int start_idx)
index 899579830536f2245316203e2662f2211697c553..b7625a9ac66ab5384727cc83496223be3aedbe92 100644 (file)
@@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d)
 
 bool rmi_is_physical_device(struct device *dev);
 
+/**
+ * rmi_reset - reset a RMI4 device
+ * @d: Pointer to an RMI device
+ *
+ * Calls for a reset of each function implemented by a specific device.
+ * Returns 0 on success or a negative error code.
+ */
+static inline int rmi_reset(struct rmi_device *d)
+{
+       return d->driver->reset_handler(d);
+}
+
 /**
  * rmi_read - read a single byte
  * @d: Pointer to an RMI device
index 4a88312fbd25405051f9ef422b4a71d95059c7a2..11447ab1055cd4beadf7eca752bdf9494d76cef1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/bitmap.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/of.h>
 #define RMI_DEVICE_RESET_CMD   0x01
 #define DEFAULT_RESET_DELAY_MS 100
 
-static void rmi_free_function_list(struct rmi_device *rmi_dev)
+void rmi_free_function_list(struct rmi_device *rmi_dev)
 {
        struct rmi_function *fn, *tmp;
        struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
 
+       rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
+
+       devm_kfree(&rmi_dev->dev, data->irq_memory);
+       data->irq_memory = NULL;
+       data->irq_status = NULL;
+       data->fn_irq_bits = NULL;
+       data->current_irq_mask = NULL;
+       data->new_irq_mask = NULL;
+
        data->f01_container = NULL;
+       data->f34_container = NULL;
 
        /* Doing it in the reverse order so F01 will be removed last */
        list_for_each_entry_safe_reverse(fn, tmp,
@@ -133,7 +144,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
        }
 }
 
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 {
        struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
        struct device *dev = &rmi_dev->dev;
@@ -143,7 +154,7 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
        if (!data)
                return 0;
 
-       if (!rmi_dev->xport->attn_data) {
+       if (!data->attn_data.data) {
                error = rmi_read_block(rmi_dev,
                                data->f01_container->fd.data_base_addr + 1,
                                data->irq_status, data->num_of_irq_regs);
@@ -178,7 +189,81 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+                      void *data, size_t size)
+{
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data;
+       void *fifo_data;
+
+       if (!drvdata->enabled)
+               return;
+
+       fifo_data = kmemdup(data, size, GFP_ATOMIC);
+       if (!fifo_data)
+               return;
+
+       attn_data.irq_status = irq_status;
+       attn_data.size = size;
+       attn_data.data = fifo_data;
+
+       kfifo_put(&drvdata->attn_fifo, attn_data);
+}
+EXPORT_SYMBOL_GPL(rmi_set_attn_data);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+       struct rmi_device *rmi_dev = dev_id;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data = {0};
+       int ret, count;
+
+       count = kfifo_get(&drvdata->attn_fifo, &attn_data);
+       if (count) {
+               *(drvdata->irq_status) = attn_data.irq_status;
+               drvdata->attn_data = attn_data;
+       }
+
+       ret = rmi_process_interrupt_requests(rmi_dev);
+       if (ret)
+               rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+                       "Failed to process interrupt request: %d\n", ret);
+
+       if (count)
+               kfree(attn_data.data);
+
+       if (!kfifo_is_empty(&drvdata->attn_fifo))
+               return rmi_irq_fn(irq, dev_id);
+
+       return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int irq_flags = irq_get_trigger_type(pdata->irq);
+       int ret;
+
+       if (!irq_flags)
+               irq_flags = IRQF_TRIGGER_LOW;
+
+       ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+                                       rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+                                       dev_name(rmi_dev->xport->dev),
+                                       rmi_dev);
+       if (ret < 0) {
+               dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
+                       pdata->irq);
+
+               return ret;
+       }
+
+       data->enabled = true;
+
+       return 0;
+}
 
 static int suspend_one_function(struct rmi_function *fn)
 {
@@ -248,7 +333,7 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
        return 0;
 }
 
-static int enable_sensor(struct rmi_device *rmi_dev)
+int rmi_enable_sensor(struct rmi_device *rmi_dev)
 {
        int retval = 0;
 
@@ -379,8 +464,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)
        return 0;
 }
 
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
-                       u16 pdt_address)
+static int rmi_read_pdt_entry(struct rmi_device *rmi_dev,
+                             struct pdt_entry *entry, u16 pdt_address)
 {
        u8 buf[RMI_PDT_ENTRY_SIZE];
        int error;
@@ -403,7 +488,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_read_pdt_entry);
 
 static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
                                      struct rmi_function_descriptor *fd)
@@ -422,6 +506,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt,
 
 static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
                             int page,
+                            int *empty_pages,
                             void *ctx,
                             int (*callback)(struct rmi_device *rmi_dev,
                                             void *ctx,
@@ -449,20 +534,30 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
                        return retval;
        }
 
-       return (data->f01_bootloader_mode || addr == pdt_start) ?
+       /*
+        * Count number of empty PDT pages. If a gap of two pages
+        * or more is found, stop scanning.
+        */
+       if (addr == pdt_start)
+               ++*empty_pages;
+       else
+               *empty_pages = 0;
+
+       return (data->bootloader_mode || *empty_pages >= 2) ?
                                        RMI_SCAN_DONE : RMI_SCAN_CONTINUE;
 }
 
-static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
-                       int (*callback)(struct rmi_device *rmi_dev,
-                                       void *ctx,
-                                       const struct pdt_entry *entry))
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+                int (*callback)(struct rmi_device *rmi_dev,
+                void *ctx, const struct pdt_entry *entry))
 {
        int page;
+       int empty_pages = 0;
        int retval = RMI_SCAN_DONE;
 
        for (page = 0; page <= RMI4_MAX_PAGE; page++) {
-               retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback);
+               retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages,
+                                          ctx, callback);
                if (retval != RMI_SCAN_CONTINUE)
                        break;
        }
@@ -600,7 +695,6 @@ free_struct_buff:
        kfree(struct_buf);
        return ret;
 }
-EXPORT_SYMBOL_GPL(rmi_read_register_desc);
 
 const struct rmi_register_desc_item *rmi_get_register_desc_item(
                                struct rmi_register_descriptor *rdesc, u16 reg)
@@ -616,7 +710,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item(
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL(rmi_get_register_desc_item);
 
 size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
 {
@@ -630,7 +723,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
        }
        return size;
 }
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size);
 
 /* Compute the register offset relative to the base address */
 int rmi_register_desc_calc_reg_offset(
@@ -648,7 +740,6 @@ int rmi_register_desc_calc_reg_offset(
        }
        return -1;
 }
-EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset);
 
 bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
        u8 subpacket)
@@ -657,51 +748,55 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
                                subpacket) == subpacket;
 }
 
-/* Indicates that flash programming is enabled (bootloader mode). */
-#define RMI_F01_STATUS_BOOTLOADER(status)      (!!((status) & 0x40))
-
-/*
- * Given the PDT entry for F01, read the device status register to determine
- * if we're stuck in bootloader mode or not.
- *
- */
 static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,
                                     const struct pdt_entry *pdt)
 {
-       int error;
-       u8 device_status;
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int ret;
+       u8 status;
 
-       error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start,
-                        &device_status);
-       if (error) {
-               dev_err(&rmi_dev->dev,
-                       "Failed to read device status: %d.\n", error);
-               return error;
+       if (pdt->function_number == 0x34 && pdt->function_version > 1) {
+               ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+               if (ret) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F34 status: %d.\n", ret);
+                       return ret;
+               }
+
+               if (status & BIT(7))
+                       data->bootloader_mode = true;
+       } else if (pdt->function_number == 0x01) {
+               ret = rmi_read(rmi_dev, pdt->data_base_addr, &status);
+               if (ret) {
+                       dev_err(&rmi_dev->dev,
+                               "Failed to read F01 status: %d.\n", ret);
+                       return ret;
+               }
+
+               if (status & BIT(6))
+                       data->bootloader_mode = true;
        }
 
-       return RMI_F01_STATUS_BOOTLOADER(device_status);
+       return 0;
 }
 
 static int rmi_count_irqs(struct rmi_device *rmi_dev,
                         void *ctx, const struct pdt_entry *pdt)
 {
-       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
        int *irq_count = ctx;
+       int ret;
 
        *irq_count += pdt->interrupt_source_count;
-       if (pdt->function_number == 0x01) {
-               data->f01_bootloader_mode =
-                       rmi_check_bootloader_mode(rmi_dev, pdt);
-               if (data->f01_bootloader_mode)
-                       dev_warn(&rmi_dev->dev,
-                               "WARNING: RMI4 device is in bootloader mode!\n");
-       }
+
+       ret = rmi_check_bootloader_mode(rmi_dev, pdt);
+       if (ret < 0)
+               return ret;
 
        return RMI_SCAN_CONTINUE;
 }
 
-static int rmi_initial_reset(struct rmi_device *rmi_dev,
-                            void *ctx, const struct pdt_entry *pdt)
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+                     const struct pdt_entry *pdt)
 {
        int error;
 
@@ -720,6 +815,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
                        return RMI_SCAN_DONE;
                }
 
+               rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n");
                error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1);
                if (error) {
                        dev_err(&rmi_dev->dev,
@@ -776,6 +872,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
 
        if (pdt->function_number == 0x01)
                data->f01_container = fn;
+       else if (pdt->function_number == 0x34)
+               data->f34_container = fn;
 
        list_add_tail(&fn->node, &data->function_list);
 
@@ -786,23 +884,95 @@ err_put_fn:
        return error;
 }
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
 {
-       int retval = 0;
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       int irq = pdata->irq;
+       int irq_flags;
+       int retval;
+
+       mutex_lock(&data->enabled_mutex);
+
+       if (data->enabled)
+               goto out;
+
+       enable_irq(irq);
+       data->enabled = true;
+       if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+               retval = disable_irq_wake(irq);
+               if (!retval)
+                       dev_warn(&rmi_dev->dev,
+                                "Failed to disable irq for wake: %d\n",
+                                retval);
+       }
+
+       /*
+        * Call rmi_process_interrupt_requests() after enabling irq,
+        * otherwise we may lose interrupt on edge-triggered systems.
+        */
+       irq_flags = irq_get_trigger_type(pdata->irq);
+       if (irq_flags & IRQ_TYPE_EDGE_BOTH)
+               rmi_process_interrupt_requests(rmi_dev);
+
+out:
+       mutex_unlock(&data->enabled_mutex);
+}
+
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
+{
+       struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+       struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+       struct rmi4_attn_data attn_data = {0};
+       int irq = pdata->irq;
+       int retval, count;
+
+       mutex_lock(&data->enabled_mutex);
+
+       if (!data->enabled)
+               goto out;
+
+       data->enabled = false;
+       disable_irq(irq);
+       if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+               retval = enable_irq_wake(irq);
+               if (!retval)
+                       dev_warn(&rmi_dev->dev,
+                                "Failed to enable irq for wake: %d\n",
+                                retval);
+       }
+
+       /* make sure the fifo is clean */
+       while (!kfifo_is_empty(&data->attn_fifo)) {
+               count = kfifo_get(&data->attn_fifo, &attn_data);
+               if (count)
+                       kfree(attn_data.data);
+       }
+
+out:
+       mutex_unlock(&data->enabled_mutex);
+}
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+{
+       int retval;
 
        retval = rmi_suspend_functions(rmi_dev);
        if (retval)
                dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
                        retval);
 
+       rmi_disable_irq(rmi_dev, enable_wake);
        return retval;
 }
 EXPORT_SYMBOL_GPL(rmi_driver_suspend);
 
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
 {
        int retval;
 
+       rmi_enable_irq(rmi_dev, clear_wake);
+
        retval = rmi_resume_functions(rmi_dev);
        if (retval)
                dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -816,6 +986,9 @@ static int rmi_driver_remove(struct device *dev)
 {
        struct rmi_device *rmi_dev = to_rmi_device(dev);
 
+       rmi_disable_irq(rmi_dev, false);
+
+       rmi_f34_remove_sysfs(rmi_dev);
        rmi_free_function_list(rmi_dev);
 
        return 0;
@@ -842,15 +1015,95 @@ static inline int rmi_driver_of_probe(struct device *dev,
 }
 #endif
 
+int rmi_probe_interrupts(struct rmi_driver_data *data)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count;
+       size_t size;
+       int retval;
+
+       /*
+        * We need to count the IRQs and allocate their storage before scanning
+        * the PDT and creating the function entries, because adding a new
+        * function can trigger events that result in the IRQ related storage
+        * being accessed.
+        */
+       rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
+       irq_count = 0;
+       data->bootloader_mode = false;
+
+       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
+       if (retval < 0) {
+               dev_err(dev, "IRQ counting failed with code %d.\n", retval);
+               return retval;
+       }
+
+       if (data->bootloader_mode)
+               dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
+
+       data->irq_count = irq_count;
+       data->num_of_irq_regs = (data->irq_count + 7) / 8;
+
+       size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
+       data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
+       if (!data->irq_memory) {
+               dev_err(dev, "Failed to allocate memory for irq masks.\n");
+               return retval;
+       }
+
+       data->irq_status        = data->irq_memory + size * 0;
+       data->fn_irq_bits       = data->irq_memory + size * 1;
+       data->current_irq_mask  = data->irq_memory + size * 2;
+       data->new_irq_mask      = data->irq_memory + size * 3;
+
+       return retval;
+}
+
+int rmi_init_functions(struct rmi_driver_data *data)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       int irq_count;
+       int retval;
+
+       irq_count = 0;
+       rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
+       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
+       if (retval < 0) {
+               dev_err(dev, "Function creation failed with code %d.\n",
+                       retval);
+               goto err_destroy_functions;
+       }
+
+       if (!data->f01_container) {
+               dev_err(dev, "Missing F01 container!\n");
+               retval = -EINVAL;
+               goto err_destroy_functions;
+       }
+
+       retval = rmi_read_block(rmi_dev,
+                               data->f01_container->fd.control_base_addr + 1,
+                               data->current_irq_mask, data->num_of_irq_regs);
+       if (retval < 0) {
+               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
+                       __func__);
+               goto err_destroy_functions;
+       }
+
+       return 0;
+
+err_destroy_functions:
+       rmi_free_function_list(rmi_dev);
+       return retval;
+}
+
 static int rmi_driver_probe(struct device *dev)
 {
        struct rmi_driver *rmi_driver;
        struct rmi_driver_data *data;
        struct rmi_device_platform_data *pdata;
        struct rmi_device *rmi_dev;
-       size_t size;
-       void *irq_memory;
-       int irq_count;
        int retval;
 
        rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n",
@@ -916,35 +1169,12 @@ static int rmi_driver_probe(struct device *dev)
                         PDT_PROPERTIES_LOCATION, retval);
        }
 
-       /*
-        * We need to count the IRQs and allocate their storage before scanning
-        * the PDT and creating the function entries, because adding a new
-        * function can trigger events that result in the IRQ related storage
-        * being accessed.
-        */
-       rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n");
-       irq_count = 0;
-       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
-       if (retval < 0) {
-               dev_err(dev, "IRQ counting failed with code %d.\n", retval);
-               goto err;
-       }
-       data->irq_count = irq_count;
-       data->num_of_irq_regs = (data->irq_count + 7) / 8;
-
        mutex_init(&data->irq_mutex);
+       mutex_init(&data->enabled_mutex);
 
-       size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long);
-       irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
-       if (!irq_memory) {
-               dev_err(dev, "Failed to allocate memory for irq masks.\n");
+       retval = rmi_probe_interrupts(data);
+       if (retval)
                goto err;
-       }
-
-       data->irq_status        = irq_memory + size * 0;
-       data->fn_irq_bits       = irq_memory + size * 1;
-       data->current_irq_mask  = irq_memory + size * 2;
-       data->new_irq_mask      = irq_memory + size * 3;
 
        if (rmi_dev->xport->input) {
                /*
@@ -961,36 +1191,20 @@ static int rmi_driver_probe(struct device *dev)
                        dev_err(dev, "%s: Failed to allocate input device.\n",
                                __func__);
                        retval = -ENOMEM;
-                       goto err_destroy_functions;
+                       goto err;
                }
                rmi_driver_set_input_params(rmi_dev, data->input);
                data->input->phys = devm_kasprintf(dev, GFP_KERNEL,
                                                "%s/input0", dev_name(dev));
        }
 
-       irq_count = 0;
-       rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions.");
-       retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
-       if (retval < 0) {
-               dev_err(dev, "Function creation failed with code %d.\n",
-                       retval);
-               goto err_destroy_functions;
-       }
-
-       if (!data->f01_container) {
-               dev_err(dev, "Missing F01 container!\n");
-               retval = -EINVAL;
-               goto err_destroy_functions;
-       }
+       retval = rmi_init_functions(data);
+       if (retval)
+               goto err;
 
-       retval = rmi_read_block(rmi_dev,
-                               data->f01_container->fd.control_base_addr + 1,
-                               data->current_irq_mask, data->num_of_irq_regs);
-       if (retval < 0) {
-               dev_err(dev, "%s: Failed to read current IRQ mask.\n",
-                       __func__);
-               goto err_destroy_functions;
-       }
+       retval = rmi_f34_create_sysfs(rmi_dev);
+       if (retval)
+               goto err;
 
        if (data->input) {
                rmi_driver_set_input_name(rmi_dev, data->input);
@@ -1003,9 +1217,13 @@ static int rmi_driver_probe(struct device *dev)
                }
        }
 
+       retval = rmi_irq_init(rmi_dev);
+       if (retval < 0)
+               goto err_destroy_functions;
+
        if (data->f01_container->dev.driver)
                /* Driver already bound, so enable ATTN now. */
-               return enable_sensor(rmi_dev);
+               return rmi_enable_sensor(rmi_dev);
 
        return 0;
 
index 8dfbebe9bf86ae96d07a922e28bccfa0b66ebe75..24f8f764d171cafb18fbc878b707006ecdfcc658 100644 (file)
@@ -51,9 +51,6 @@ struct pdt_entry {
        u8 function_number;
 };
 
-int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
-                       u16 pdt_address);
-
 #define RMI_REG_DESC_PRESENSE_BITS     (32 * BITS_PER_BYTE)
 #define RMI_REG_DESC_SUBPACKET_BITS    (37 * BITS_PER_BYTE)
 
@@ -95,12 +92,40 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
 bool rmi_is_physical_driver(struct device_driver *);
 int rmi_register_physical_driver(void);
 void rmi_unregister_physical_driver(void);
+void rmi_free_function_list(struct rmi_device *rmi_dev);
+int rmi_enable_sensor(struct rmi_device *rmi_dev);
+int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
+                int (*callback)(struct rmi_device *rmi_dev, void *ctx,
+                const struct pdt_entry *entry));
+int rmi_probe_interrupts(struct rmi_driver_data *data);
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_init_functions(struct rmi_driver_data *data);
+int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
+                     const struct pdt_entry *pdt);
 
 char *rmi_f01_get_product_ID(struct rmi_function *fn);
 
+#ifdef CONFIG_RMI4_F34
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
+#else
+static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+       return 0;
+}
+
+static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+}
+#endif /* CONFIG_RMI_F34 */
+
 extern struct rmi_function_handler rmi_f01_handler;
+extern struct rmi_function_handler rmi_f03_handler;
 extern struct rmi_function_handler rmi_f11_handler;
 extern struct rmi_function_handler rmi_f12_handler;
 extern struct rmi_function_handler rmi_f30_handler;
+extern struct rmi_function_handler rmi_f34_handler;
 extern struct rmi_function_handler rmi_f54_handler;
+extern struct rmi_function_handler rmi_f55_handler;
 #endif
index b5d2dfc23bad9fc7d5a626762518817713adbefa..18baf4ceb9407e6cad636ec9d41f638b9aba2131 100644 (file)
@@ -62,6 +62,8 @@ struct f01_basic_properties {
 #define RMI_F01_STATUS_CODE(status)            ((status) & 0x0f)
 /* The device has lost its configuration for some reason. */
 #define RMI_F01_STATUS_UNCONFIGURED(status)    (!!((status) & 0x80))
+/* The device is in bootloader mode */
+#define RMI_F01_STATUS_BOOTLOADER(status)      ((status) & 0x40)
 
 /* Control register bits */
 
@@ -326,12 +328,12 @@ static int rmi_f01_probe(struct rmi_function *fn)
        }
 
        switch (pdata->power_management.nosleep) {
-       case RMI_F01_NOSLEEP_DEFAULT:
+       case RMI_REG_STATE_DEFAULT:
                break;
-       case RMI_F01_NOSLEEP_OFF:
+       case RMI_REG_STATE_OFF:
                f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT;
                break;
-       case RMI_F01_NOSLEEP_ON:
+       case RMI_REG_STATE_ON:
                f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT;
                break;
        }
@@ -593,6 +595,10 @@ static int rmi_f01_attention(struct rmi_function *fn,
                return error;
        }
 
+       if (RMI_F01_STATUS_BOOTLOADER(device_status))
+               dev_warn(&fn->dev,
+                        "Device in bootloader mode, please update firmware\n");
+
        if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
                dev_warn(&fn->dev, "Device reset detected.\n");
                error = rmi_dev->driver->reset_handler(rmi_dev);
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
new file mode 100644 (file)
index 0000000..8a7ca3e
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2015-2016 Red Hat
+ * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.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/kernel.h>
+#include <linux/slab.h>
+#include <linux/serio.h>
+#include <linux/notifier.h>
+#include "rmi_driver.h"
+
+#define RMI_F03_RX_DATA_OFB            0x01
+#define RMI_F03_OB_SIZE                        2
+
+#define RMI_F03_OB_OFFSET              2
+#define RMI_F03_OB_DATA_OFFSET         1
+#define RMI_F03_OB_FLAG_TIMEOUT                BIT(6)
+#define RMI_F03_OB_FLAG_PARITY         BIT(7)
+
+#define RMI_F03_DEVICE_COUNT           0x07
+#define RMI_F03_BYTES_PER_DEVICE       0x07
+#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
+#define RMI_F03_QUEUE_LENGTH           0x0F
+
+struct f03_data {
+       struct rmi_function *fn;
+
+       struct serio *serio;
+
+       u8 device_count;
+       u8 rx_queue_length;
+};
+
+static int rmi_f03_pt_write(struct serio *id, unsigned char val)
+{
+       struct f03_data *f03 = id->port_data;
+       int error;
+
+       rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
+               "%s: Wrote %.2hhx to PS/2 passthrough address",
+               __func__, val);
+
+       error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
+       if (error) {
+               dev_err(&f03->fn->dev,
+                       "%s: Failed to write to F03 TX register (%d).\n",
+                       __func__, error);
+               return error;
+       }
+
+       return 0;
+}
+
+static int rmi_f03_initialize(struct f03_data *f03)
+{
+       struct rmi_function *fn = f03->fn;
+       struct device *dev = &fn->dev;
+       int error;
+       u8 bytes_per_device;
+       u8 query1;
+       u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
+       size_t query2_len;
+
+       error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
+       if (error) {
+               dev_err(dev, "Failed to read query register (%d).\n", error);
+               return error;
+       }
+
+       f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
+       bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
+                               RMI_F03_BYTES_PER_DEVICE;
+
+       query2_len = f03->device_count * bytes_per_device;
+
+       /*
+        * The first generation of image sensors don't have a second part to
+        * their f03 query, as such we have to set some of these values manually
+        */
+       if (query2_len < 1) {
+               f03->device_count = 1;
+               f03->rx_queue_length = 7;
+       } else {
+               error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
+                                      query2, query2_len);
+               if (error) {
+                       dev_err(dev,
+                               "Failed to read second set of query registers (%d).\n",
+                               error);
+                       return error;
+               }
+
+               f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
+       }
+
+       return 0;
+}
+
+static int rmi_f03_register_pt(struct f03_data *f03)
+{
+       struct serio *serio;
+
+       serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+       if (!serio)
+               return -ENOMEM;
+
+       serio->id.type = SERIO_8042;
+       serio->write = rmi_f03_pt_write;
+       serio->port_data = f03;
+
+       strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
+               sizeof(serio->name));
+       strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
+               sizeof(serio->phys));
+       serio->dev.parent = &f03->fn->dev;
+
+       f03->serio = serio;
+
+       serio_register_port(serio);
+
+       return 0;
+}
+
+static int rmi_f03_probe(struct rmi_function *fn)
+{
+       struct device *dev = &fn->dev;
+       struct f03_data *f03;
+       int error;
+
+       f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
+       if (!f03)
+               return -ENOMEM;
+
+       f03->fn = fn;
+
+       error = rmi_f03_initialize(f03);
+       if (error < 0)
+               return error;
+
+       if (f03->device_count != 1)
+               dev_warn(dev, "found %d devices on PS/2 passthrough",
+                        f03->device_count);
+
+       dev_set_drvdata(dev, f03);
+
+       error = rmi_f03_register_pt(f03);
+       if (error)
+               return error;
+
+       return 0;
+}
+
+static int rmi_f03_config(struct rmi_function *fn)
+{
+       fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+       return 0;
+}
+
+static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
+       struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+       u16 data_addr = fn->fd.data_base_addr;
+       const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
+       u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
+       u8 ob_status;
+       u8 ob_data;
+       unsigned int serio_flags;
+       int i;
+       int error;
+
+       if (!rmi_dev)
+               return -ENODEV;
+
+       if (drvdata->attn_data.data) {
+               /* First grab the data passed by the transport device */
+               if (drvdata->attn_data.size < ob_len) {
+                       dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
+                       return 0;
+               }
+
+               memcpy(obs, drvdata->attn_data.data, ob_len);
+
+               drvdata->attn_data.data += ob_len;
+               drvdata->attn_data.size -= ob_len;
+       } else {
+               /* Grab all of the data registers, and check them for data */
+               error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
+                                      &obs, ob_len);
+               if (error) {
+                       dev_err(&fn->dev,
+                               "%s: Failed to read F03 output buffers: %d\n",
+                               __func__, error);
+                       serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
+                       return error;
+               }
+       }
+
+       for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
+               ob_status = obs[i];
+               ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
+               serio_flags = 0;
+
+               if (!(ob_status & RMI_F03_RX_DATA_OFB))
+                       continue;
+
+               if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
+                       serio_flags |= SERIO_TIMEOUT;
+               if (ob_status & RMI_F03_OB_FLAG_PARITY)
+                       serio_flags |= SERIO_PARITY;
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev,
+                       "%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
+                       __func__, ob_data,
+                       serio_flags & SERIO_TIMEOUT ?  'Y' : 'N',
+                       serio_flags & SERIO_PARITY ? 'Y' : 'N');
+
+               serio_interrupt(f03->serio, ob_data, serio_flags);
+       }
+
+       return 0;
+}
+
+static void rmi_f03_remove(struct rmi_function *fn)
+{
+       struct f03_data *f03 = dev_get_drvdata(&fn->dev);
+
+       serio_unregister_port(f03->serio);
+}
+
+struct rmi_function_handler rmi_f03_handler = {
+       .driver = {
+               .name = "rmi4_f03",
+       },
+       .func = 0x03,
+       .probe = rmi_f03_probe,
+       .config = rmi_f03_config,
+       .attention = rmi_f03_attention,
+       .remove = rmi_f03_remove,
+};
+
+MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
+MODULE_DESCRIPTION("RMI F03 module");
+MODULE_LICENSE("GPL");
index f798f427a46fde82f9580fa964c41452963c3260..bc5e37f30ac1cf4022ac5a8a17f63fb1793d2ce0 100644 (file)
@@ -571,31 +571,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger)
 
 static void rmi_f11_finger_handler(struct f11_data *f11,
                                   struct rmi_2d_sensor *sensor,
-                                  unsigned long *irq_bits, int num_irq_regs)
+                                  unsigned long *irq_bits, int num_irq_regs,
+                                  int size)
 {
        const u8 *f_state = f11->data.f_state;
        u8 finger_state;
        u8 i;
+       int abs_fingers;
+       int rel_fingers;
+       int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES;
 
        int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask,
                                  num_irq_regs * 8);
        int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask,
                                  num_irq_regs * 8);
 
-       for (i = 0; i < sensor->nbr_fingers; i++) {
-               /* Possible of having 4 fingers per f_statet register */
-               finger_state = rmi_f11_parse_finger_state(f_state, i);
-               if (finger_state == F11_RESERVED) {
-                       pr_err("Invalid finger state[%d]: 0x%02x", i,
-                               finger_state);
-                       continue;
-               }
+       if (abs_bits) {
+               if (abs_size > size)
+                       abs_fingers = size / RMI_F11_ABS_BYTES;
+               else
+                       abs_fingers = sensor->nbr_fingers;
+
+               for (i = 0; i < abs_fingers; i++) {
+                       /* Possible of having 4 fingers per f_state register */
+                       finger_state = rmi_f11_parse_finger_state(f_state, i);
+                       if (finger_state == F11_RESERVED) {
+                               pr_err("Invalid finger state[%d]: 0x%02x", i,
+                                       finger_state);
+                               continue;
+                       }
 
-               if (abs_bits)
                        rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i],
                                                        finger_state, i);
+               }
+       }
+
+       if (rel_bits) {
+               if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size)
+                       rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES;
+               else
+                       rel_fingers = sensor->nbr_fingers;
 
-               if (rel_bits)
+               for (i = 0; i < rel_fingers; i++)
                        rmi_f11_rel_pos_report(f11, i);
        }
 
@@ -611,7 +628,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11,
                                              sensor->nbr_fingers,
                                              sensor->dmax);
 
-               for (i = 0; i < sensor->nbr_fingers; i++) {
+               for (i = 0; i < abs_fingers; i++) {
                        finger_state = rmi_f11_parse_finger_state(f_state, i);
                        if (finger_state == F11_RESERVED)
                                /* no need to send twice the error */
@@ -1062,8 +1079,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
                rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata);
                if (rc)
                        return rc;
-       } else if (pdata->sensor_pdata) {
-               f11->sensor_pdata = *pdata->sensor_pdata;
+       } else {
+               f11->sensor_pdata = pdata->sensor_pdata;
        }
 
        f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait;
@@ -1124,6 +1141,8 @@ static int rmi_f11_initialize(struct rmi_function *fn)
        sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad;
        sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking;
        sensor->dmax = f11->sensor_pdata.dmax;
+       sensor->dribble = f11->sensor_pdata.dribble;
+       sensor->palm_detect = f11->sensor_pdata.palm_detect;
 
        if (f11->sens_query.has_physical_props) {
                sensor->x_mm = f11->sens_query.x_sensor_size_mm;
@@ -1191,11 +1210,33 @@ static int rmi_f11_initialize(struct rmi_function *fn)
                ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
                        sensor->axis_align.delta_y_threshold;
 
-       if (f11->sens_query.has_dribble)
-               ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6);
+       if (f11->sens_query.has_dribble) {
+               switch (sensor->dribble) {
+               case RMI_REG_STATE_OFF:
+                       ctrl->ctrl0_11[0] &= ~BIT(6);
+                       break;
+               case RMI_REG_STATE_ON:
+                       ctrl->ctrl0_11[0] |= BIT(6);
+                       break;
+               case RMI_REG_STATE_DEFAULT:
+               default:
+                       break;
+               }
+       }
 
-       if (f11->sens_query.has_palm_det)
-               ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0);
+       if (f11->sens_query.has_palm_det) {
+               switch (sensor->palm_detect) {
+               case RMI_REG_STATE_OFF:
+                       ctrl->ctrl0_11[11] &= ~BIT(0);
+                       break;
+               case RMI_REG_STATE_ON:
+                       ctrl->ctrl0_11[11] |= BIT(0);
+                       break;
+               case RMI_REG_STATE_DEFAULT:
+               default:
+                       break;
+               }
+       }
 
        rc = f11_write_control_regs(fn, &f11->sens_query,
                           &f11->dev_controls, fn->fd.query_base_addr);
@@ -1241,12 +1282,21 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
        struct f11_data *f11 = dev_get_drvdata(&fn->dev);
        u16 data_base_addr = fn->fd.data_base_addr;
        int error;
+       int valid_bytes = f11->sensor.pkt_size;
 
-       if (rmi_dev->xport->attn_data) {
-               memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data,
-                       f11->sensor.attn_size);
-               rmi_dev->xport->attn_data += f11->sensor.attn_size;
-               rmi_dev->xport->attn_size -= f11->sensor.attn_size;
+       if (drvdata->attn_data.data) {
+               /*
+                * The valid data in the attention report is less then
+                * expected. Only process the complete fingers.
+                */
+               if (f11->sensor.attn_size > drvdata->attn_data.size)
+                       valid_bytes = drvdata->attn_data.size;
+               else
+                       valid_bytes = f11->sensor.attn_size;
+               memcpy(f11->sensor.data_pkt, drvdata->attn_data.data,
+                       valid_bytes);
+               drvdata->attn_data.data += f11->sensor.attn_size;
+               drvdata->attn_data.size -= f11->sensor.attn_size;
        } else {
                error = rmi_read_block(rmi_dev,
                                data_base_addr, f11->sensor.data_pkt,
@@ -1256,7 +1306,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits)
        }
 
        rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
-                               drvdata->num_of_irq_regs);
+                               drvdata->num_of_irq_regs, valid_bytes);
 
        return 0;
 }
index 332c02f0b107c02f1ae5f5a404ed13b5ee39885d..07aff4356fe0ea751984e59fbb7292b14bf9503e 100644 (file)
@@ -26,9 +26,12 @@ enum rmi_f12_object_type {
        RMI_F12_OBJECT_SMALL_OBJECT             = 0x0D,
 };
 
+#define F12_DATA1_BYTES_PER_OBJ                        8
+
 struct f12_data {
        struct rmi_2d_sensor sensor;
        struct rmi_2d_sensor_platform_data sensor_pdata;
+       bool has_dribble;
 
        u16 data_addr;
 
@@ -68,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        u8 buf[15];
        int pitch_x = 0;
        int pitch_y = 0;
-       int clip_x_low = 0;
-       int clip_x_high = 0;
-       int clip_y_low = 0;
-       int clip_y_high = 0;
        int rx_receivers = 0;
        int tx_receivers = 0;
        int sensor_flags = 0;
@@ -124,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        }
 
        rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
-               __func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
+               __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];
@@ -146,12 +147,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
        return 0;
 }
 
-static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
+static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
 {
        int i;
        struct rmi_2d_sensor *sensor = &f12->sensor;
+       int objects = f12->data1->num_subpackets;
+
+       if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
+               objects = size / F12_DATA1_BYTES_PER_OBJ;
 
-       for (i = 0; i < f12->data1->num_subpackets; i++) {
+       for (i = 0; i < objects; i++) {
                struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
 
                obj->type = RMI_2D_OBJECT_NONE;
@@ -182,7 +187,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
 
                rmi_2d_sensor_abs_process(sensor, obj, i);
 
-               data1 += 8;
+               data1 += F12_DATA1_BYTES_PER_OBJ;
        }
 
        if (sensor->kernel_tracking)
@@ -192,7 +197,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
                                      sensor->nbr_fingers,
                                      sensor->dmax);
 
-       for (i = 0; i < sensor->nbr_fingers; i++)
+       for (i = 0; i < objects; i++)
                rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
 }
 
@@ -201,14 +206,20 @@ static int rmi_f12_attention(struct rmi_function *fn,
 {
        int retval;
        struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        struct f12_data *f12 = dev_get_drvdata(&fn->dev);
        struct rmi_2d_sensor *sensor = &f12->sensor;
-
-       if (rmi_dev->xport->attn_data) {
-               memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
-                       sensor->attn_size);
-               rmi_dev->xport->attn_data += sensor->attn_size;
-               rmi_dev->xport->attn_size -= sensor->attn_size;
+       int valid_bytes = sensor->pkt_size;
+
+       if (drvdata->attn_data.data) {
+               if (sensor->attn_size > drvdata->attn_data.size)
+                       valid_bytes = drvdata->attn_data.size;
+               else
+                       valid_bytes = sensor->attn_size;
+               memcpy(sensor->data_pkt, drvdata->attn_data.data,
+                       valid_bytes);
+               drvdata->attn_data.data += sensor->attn_size;
+               drvdata->attn_data.size -= sensor->attn_size;
        } else {
                retval = rmi_read_block(rmi_dev, f12->data_addr,
                                        sensor->data_pkt, sensor->pkt_size);
@@ -221,19 +232,83 @@ static int rmi_f12_attention(struct rmi_function *fn,
 
        if (f12->data1)
                rmi_f12_process_objects(f12,
-                       &sensor->data_pkt[f12->data1_offset]);
+                       &sensor->data_pkt[f12->data1_offset], valid_bytes);
 
        input_mt_sync_frame(sensor->input);
 
        return 0;
 }
 
+static int rmi_f12_write_control_regs(struct rmi_function *fn)
+{
+       int ret;
+       const struct rmi_register_desc_item *item;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct f12_data *f12 = dev_get_drvdata(&fn->dev);
+       int control_size;
+       char buf[3];
+       u16 control_offset = 0;
+       u8 subpacket_offset = 0;
+
+       if (f12->has_dribble
+           && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
+               item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
+               if (item) {
+                       control_offset = rmi_register_desc_calc_reg_offset(
+                                               &f12->control_reg_desc, 20);
+
+                       /*
+                        * The byte containing the EnableDribble bit will be
+                        * in either byte 0 or byte 2 of control 20. Depending
+                        * on the existence of subpacket 0. If control 20 is
+                        * larger then 3 bytes, just read the first 3.
+                        */
+                       control_size = min(item->reg_size, 3UL);
+
+                       ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
+                                       + control_offset, buf, control_size);
+                       if (ret)
+                               return ret;
+
+                       if (rmi_register_desc_has_subpacket(item, 0))
+                               subpacket_offset += 1;
+
+                       switch (f12->sensor.dribble) {
+                       case RMI_REG_STATE_OFF:
+                               buf[subpacket_offset] &= ~BIT(2);
+                               break;
+                       case RMI_REG_STATE_ON:
+                               buf[subpacket_offset] |= BIT(2);
+                               break;
+                       case RMI_REG_STATE_DEFAULT:
+                       default:
+                               break;
+                       }
+
+                       ret = rmi_write_block(rmi_dev,
+                               fn->fd.control_base_addr + control_offset,
+                               buf, control_size);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+
+}
+
 static int rmi_f12_config(struct rmi_function *fn)
 {
        struct rmi_driver *drv = fn->rmi_dev->driver;
+       int ret;
 
        drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
 
+       ret = rmi_f12_write_control_regs(fn);
+       if (ret)
+               dev_warn(&fn->dev,
+                       "Failed to write F12 control registers: %d\n", ret);
+
        return 0;
 }
 
@@ -247,7 +322,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
        const struct rmi_register_desc_item *item;
        struct rmi_2d_sensor *sensor;
        struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
-       struct rmi_transport_dev *xport = rmi_dev->xport;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        u16 data_offset = 0;
 
        rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
@@ -260,7 +335,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
        ++query_addr;
 
-       if (!(buf & 0x1)) {
+       if (!(buf & BIT(0))) {
                dev_err(&fn->dev,
                        "Behavior of F12 without register descriptors is undefined.\n");
                return -ENODEV;
@@ -270,12 +345,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
        if (!f12)
                return -ENOMEM;
 
+       f12->has_dribble = !!(buf & BIT(3));
+
        if (fn->dev.of_node) {
                ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
                if (ret)
                        return ret;
-       } else if (pdata->sensor_pdata) {
-               f12->sensor_pdata = *pdata->sensor_pdata;
+       } else {
+               f12->sensor_pdata = pdata->sensor_pdata;
        }
 
        ret = rmi_read_register_desc(rmi_dev, query_addr,
@@ -318,6 +395,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
 
        sensor->x_mm = f12->sensor_pdata.x_mm;
        sensor->y_mm = f12->sensor_pdata.y_mm;
+       sensor->dribble = f12->sensor_pdata.dribble;
 
        if (sensor->sensor_type == rmi_sensor_default)
                sensor->sensor_type =
@@ -343,7 +421,7 @@ static int rmi_f12_probe(struct rmi_function *fn)
         * HID attention reports.
         */
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
@@ -357,15 +435,15 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
@@ -377,22 +455,22 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data6 = item;
                f12->data6_offset = data_offset;
                data_offset += item->reg_size;
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data9 = item;
                f12->data9_offset = data_offset;
                data_offset += item->reg_size;
@@ -401,27 +479,27 @@ static int rmi_f12_probe(struct rmi_function *fn)
        }
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
-       if (item && !xport->attn_data)
+       if (item && !drvdata->attn_data.data)
                data_offset += item->reg_size;
 
        item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
-       if (item && !xport->attn_data) {
+       if (item && !drvdata->attn_data.data) {
                f12->data15 = item;
                f12->data15_offset = data_offset;
                data_offset += item->reg_size;
index 760aff1bc4207814ddebe1fa5e99bb9687a95189..f4b491e3e0fd4486c2680fab77515d91abaec4aa 100644 (file)
@@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
 {
        struct f30_data *f30 = dev_get_drvdata(&fn->dev);
        struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
        int retval;
        int gpiled = 0;
        int value = 0;
@@ -109,11 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
                return 0;
 
        /* Read the gpi led data. */
-       if (rmi_dev->xport->attn_data) {
-               memcpy(f30->data_regs, rmi_dev->xport->attn_data,
+       if (drvdata->attn_data.data) {
+               if (drvdata->attn_data.size < f30->register_count) {
+                       dev_warn(&fn->dev, "F30 interrupted, but data is missing\n");
+                       return 0;
+               }
+               memcpy(f30->data_regs, drvdata->attn_data.data,
                        f30->register_count);
-               rmi_dev->xport->attn_data += f30->register_count;
-               rmi_dev->xport->attn_size -= f30->register_count;
+               drvdata->attn_data.data += f30->register_count;
+               drvdata->attn_data.size -= f30->register_count;
        } else {
                retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
                        f30->data_regs, f30->register_count);
@@ -192,7 +197,7 @@ static int rmi_f30_config(struct rmi_function *fn)
                                rmi_get_platform_data(fn->rmi_dev);
        int error;
 
-       if (pdata->f30_data && pdata->f30_data->disable) {
+       if (pdata->f30_data.disable) {
                drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
        } else {
                /* Write Control Register values back to device */
@@ -351,7 +356,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
        f30->gpioled_key_map = (u16 *)map_memory;
 
        pdata = rmi_get_platform_data(rmi_dev);
-       if (pdata && f30->has_gpio) {
+       if (f30->has_gpio) {
                button = BTN_LEFT;
                for (i = 0; i < f30->gpioled_count; i++) {
                        if (rmi_f30_is_valid_button(i, f30->ctrl)) {
@@ -362,8 +367,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn)
                                 * f30->has_mech_mouse_btns, but I am
                                 * not sure, so use only the pdata info
                                 */
-                               if (pdata->f30_data &&
-                                   pdata->f30_data->buttonpad)
+                               if (pdata->f30_data.buttonpad)
                                        break;
                        }
                }
@@ -378,7 +382,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
        const struct rmi_device_platform_data *pdata =
                                rmi_get_platform_data(fn->rmi_dev);
 
-       if (pdata->f30_data && pdata->f30_data->disable)
+       if (pdata->f30_data.disable)
                return 0;
 
        rc = rmi_f30_initialize(fn);
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
new file mode 100644 (file)
index 0000000..9774dfb
--- /dev/null
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <asm/unaligned.h>
+#include <linux/bitops.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34_write_bootloader_id(struct f34_data *f34)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       u8 bootloader_id[F34_BOOTLOADER_ID_LEN];
+       int ret;
+
+       ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr,
+                            bootloader_id, sizeof(bootloader_id));
+       if (ret) {
+               dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n",
+                               __func__, ret);
+               return ret;
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n",
+                       __func__, bootloader_id[0], bootloader_id[1]);
+
+       ret = rmi_write_block(rmi_dev,
+                             fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET,
+                             bootloader_id, sizeof(bootloader_id));
+       if (ret) {
+               dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34_command(struct f34_data *f34, u8 command,
+                          unsigned int timeout, bool write_bl_id)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       int ret;
+
+       if (write_bl_id) {
+               ret = rmi_f34_write_bootloader_id(f34);
+               if (ret)
+                       return ret;
+       }
+
+       init_completion(&f34->v5.cmd_done);
+
+       ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+       if (ret) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read cmd register: %d (command %#02x)\n",
+                       __func__, ret, command);
+               return ret;
+       }
+
+       f34->v5.status |= command & 0x0f;
+
+       ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "Failed to write F34 command %#02x: %d\n",
+                       command, ret);
+               return ret;
+       }
+
+       if (!wait_for_completion_timeout(&f34->v5.cmd_done,
+                               msecs_to_jiffies(timeout))) {
+
+               ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status);
+               if (ret) {
+                       dev_err(&f34->fn->dev,
+                               "%s: cmd %#02x timed out: %d\n",
+                               __func__, command, ret);
+                       return ret;
+               }
+
+               if (f34->v5.status & 0x7f) {
+                       dev_err(&f34->fn->dev,
+                               "%s: cmd %#02x timed out, status: %#02x\n",
+                               __func__, command, f34->v5.status);
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits)
+{
+       struct f34_data *f34 = dev_get_drvdata(&fn->dev);
+       int ret;
+
+       if (f34->bl_version != 5)
+               return 0;
+
+       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);
+
+       return 0;
+}
+
+static int rmi_f34_write_blocks(struct f34_data *f34, const void *data,
+                               int block_count, u8 command)
+{
+       struct rmi_function *fn = f34->fn;
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET;
+       u8 start_address[] = { 0, 0 };
+       int i;
+       int ret;
+
+       ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr,
+                             start_address, sizeof(start_address));
+       if (ret) {
+               dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < block_count; i++) {
+               ret = rmi_write_block(rmi_dev, address,
+                                     data, f34->v5.block_size);
+               if (ret) {
+                       dev_err(&fn->dev,
+                               "failed to write block #%d: %d\n", i, ret);
+                       return ret;
+               }
+
+               ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false);
+               if (ret) {
+                       dev_err(&fn->dev,
+                               "Failed to write command for block #%d: %d\n",
+                               i, ret);
+                       return ret;
+               }
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n",
+                       i + 1, block_count);
+
+               data += f34->v5.block_size;
+       }
+
+       return 0;
+}
+
+static int rmi_f34_write_firmware(struct f34_data *f34, const void *data)
+{
+       return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks,
+                                   F34_WRITE_FW_BLOCK);
+}
+
+static int rmi_f34_write_config(struct f34_data *f34, const void *data)
+{
+       return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks,
+                                   F34_WRITE_CONFIG_BLOCK);
+}
+
+int rmi_f34_enable_flash(struct f34_data *f34)
+{
+       return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG,
+                              F34_ENABLE_WAIT_MS, true);
+}
+
+static int rmi_f34_flash_firmware(struct f34_data *f34,
+                                 const struct rmi_f34_firmware *syn_fw)
+{
+       struct rmi_function *fn = f34->fn;
+       int ret;
+
+       if (syn_fw->image_size) {
+               dev_info(&fn->dev, "Erasing firmware...\n");
+               ret = rmi_f34_command(f34, F34_ERASE_ALL,
+                                     F34_ERASE_WAIT_MS, true);
+               if (ret)
+                       return ret;
+
+               dev_info(&fn->dev, "Writing firmware (%d bytes)...\n",
+                        syn_fw->image_size);
+               ret = rmi_f34_write_firmware(f34, syn_fw->data);
+               if (ret)
+                       return ret;
+       }
+
+       if (syn_fw->config_size) {
+               /*
+                * We only need to erase config if we haven't updated
+                * firmware.
+                */
+               if (!syn_fw->image_size) {
+                       dev_info(&fn->dev, "Erasing config...\n");
+                       ret = rmi_f34_command(f34, F34_ERASE_CONFIG,
+                                             F34_ERASE_WAIT_MS, true);
+                       if (ret)
+                               return ret;
+               }
+
+               dev_info(&fn->dev, "Writing config (%d bytes)...\n",
+                        syn_fw->config_size);
+               ret = rmi_f34_write_config(f34,
+                               &syn_fw->data[syn_fw->image_size]);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw)
+{
+       const struct rmi_f34_firmware *syn_fw;
+       int ret;
+
+       syn_fw = (const struct rmi_f34_firmware *)fw->data;
+       BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
+                       F34_FW_IMAGE_OFFSET);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n",
+               (int)fw->size,
+               le32_to_cpu(syn_fw->checksum),
+               le32_to_cpu(syn_fw->image_size),
+               le32_to_cpu(syn_fw->config_size));
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n",
+               syn_fw->bootloader_version,
+               (int)sizeof(syn_fw->product_id), syn_fw->product_id,
+               syn_fw->product_info[0], syn_fw->product_info[1]);
+
+       if (syn_fw->image_size &&
+           syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) {
+               dev_err(&f34->fn->dev,
+                       "Bad firmware image: fw size %d, expected %d\n",
+                       syn_fw->image_size,
+                       f34->v5.fw_blocks * f34->v5.block_size);
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       if (syn_fw->config_size &&
+           syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) {
+               dev_err(&f34->fn->dev,
+                       "Bad firmware image: config size %d, expected %d\n",
+                       syn_fw->config_size,
+                       f34->v5.config_blocks * f34->v5.block_size);
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       if (syn_fw->image_size && !syn_fw->config_size) {
+               dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
+               ret = -EILSEQ;
+               goto out;
+       }
+
+       dev_info(&f34->fn->dev, "Firmware image OK\n");
+       mutex_lock(&f34->v5.flash_mutex);
+
+       ret = rmi_f34_flash_firmware(f34, syn_fw);
+
+       mutex_unlock(&f34->v5.flash_mutex);
+
+out:
+       return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+                              const struct firmware *fw)
+{
+       struct rmi_device *rmi_dev = data->rmi_dev;
+       struct device *dev = &rmi_dev->dev;
+       struct f34_data *f34;
+       int ret;
+
+       if (!data->f34_container) {
+               dev_warn(dev, "%s: No F34 present!\n", __func__);
+               return -EINVAL;
+       }
+
+       f34 = dev_get_drvdata(&data->f34_container->dev);
+
+       if (f34->bl_version == 7) {
+               if (data->pdt_props & HAS_BSR) {
+                       dev_err(dev, "%s: LTS not supported\n", __func__);
+                       return -ENODEV;
+               }
+       } else if (f34->bl_version != 5) {
+               dev_warn(dev, "F34 V%d not supported!\n",
+                        data->f34_container->fd.function_version);
+               return -ENODEV;
+       }
+
+       /* Enter flash mode */
+       if (f34->bl_version == 7)
+               ret = rmi_f34v7_start_reflash(f34, fw);
+       else
+               ret = rmi_f34_enable_flash(f34);
+       if (ret)
+               return ret;
+
+       rmi_disable_irq(rmi_dev, false);
+
+       /* Tear down functions and re-probe */
+       rmi_free_function_list(rmi_dev);
+
+       ret = rmi_probe_interrupts(data);
+       if (ret)
+               return ret;
+
+       ret = rmi_init_functions(data);
+       if (ret)
+               return ret;
+
+       if (!data->bootloader_mode || !data->f34_container) {
+               dev_warn(dev, "%s: No F34 present or not in bootloader!\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       rmi_enable_irq(rmi_dev, false);
+
+       f34 = dev_get_drvdata(&data->f34_container->dev);
+
+       /* Perform firmware update */
+       if (f34->bl_version == 7)
+               ret = rmi_f34v7_do_reflash(f34, fw);
+       else
+               ret = rmi_f34_update_firmware(f34, fw);
+
+       dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret);
+
+       rmi_disable_irq(rmi_dev, false);
+
+       /* Re-probe */
+       rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n");
+       rmi_free_function_list(rmi_dev);
+
+       ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset);
+       if (ret < 0)
+               dev_warn(dev, "RMI reset failed!\n");
+
+       ret = rmi_probe_interrupts(data);
+       if (ret)
+               return ret;
+
+       ret = rmi_init_functions(data);
+       if (ret)
+               return ret;
+
+       rmi_enable_irq(rmi_dev, false);
+
+       if (data->f01_container->dev.driver)
+               /* Driver already bound, so enable ATTN now. */
+               return rmi_enable_sensor(rmi_dev);
+
+       rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__);
+
+       return ret;
+}
+
+static int rmi_firmware_update(struct rmi_driver_data *data,
+                              const struct firmware *fw);
+
+static ssize_t rmi_driver_update_fw_store(struct device *dev,
+                                         struct device_attribute *dattr,
+                                         const char *buf, size_t count)
+{
+       struct rmi_driver_data *data = dev_get_drvdata(dev);
+       char fw_name[NAME_MAX];
+       const struct firmware *fw;
+       size_t copy_count = count;
+       int ret;
+
+       if (count == 0 || count >= NAME_MAX)
+               return -EINVAL;
+
+       if (buf[count - 1] == '\0' || buf[count - 1] == '\n')
+               copy_count -= 1;
+
+       strncpy(fw_name, buf, copy_count);
+       fw_name[copy_count] = '\0';
+
+       ret = request_firmware(&fw, fw_name, dev);
+       if (ret)
+               return ret;
+
+       dev_info(dev, "Flashing %s\n", fw_name);
+
+       ret = rmi_firmware_update(data, fw);
+
+       release_firmware(fw);
+
+       return ret ?: count;
+}
+
+static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
+
+static struct attribute *rmi_firmware_attrs[] = {
+       &dev_attr_update_fw.attr,
+       NULL
+};
+
+static struct attribute_group rmi_firmware_attr_group = {
+       .attrs = rmi_firmware_attrs,
+};
+
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+       struct f34_data *f34;
+       unsigned char f34_queries[9];
+       bool has_config_id;
+       u8 version = fn->fd.function_version;
+       int ret;
+
+       f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+       if (!f34)
+               return -ENOMEM;
+
+       f34->fn = fn;
+       dev_set_drvdata(&fn->dev, f34);
+
+       /* v5 code only supported version 0, try V7 probe */
+       if (version > 0)
+               return rmi_f34v7_probe(f34);
+       else if (version != 0)
+               return -ENODEV;
+
+       f34->bl_version = 5;
+
+       ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+                            f34_queries, sizeof(f34_queries));
+       if (ret) {
+               dev_err(&fn->dev, "%s: Failed to query properties\n",
+                       __func__);
+               return ret;
+       }
+
+       snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
+                "%c%c", f34_queries[0], f34_queries[1]);
+
+       mutex_init(&f34->v5.flash_mutex);
+       init_completion(&f34->v5.cmd_done);
+
+       f34->v5.block_size = get_unaligned_le16(&f34_queries[3]);
+       f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]);
+       f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]);
+       f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET +
+               f34->v5.block_size;
+       has_config_id = f34_queries[2] & (1 << 2);
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n",
+               f34->bootloader_id);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n",
+               f34->v5.block_size);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n",
+               f34->v5.fw_blocks);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n",
+               f34->v5.config_blocks);
+
+       if (has_config_id) {
+               ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+                                    f34_queries, sizeof(f34_queries));
+               if (ret) {
+                       dev_err(&fn->dev, "Failed to read F34 config ID\n");
+                       return ret;
+               }
+
+               snprintf(f34->configuration_id, sizeof(f34->configuration_id),
+                        "%02x%02x%02x%02x",
+                        f34_queries[0], f34_queries[1],
+                        f34_queries[2], f34_queries[3]);
+
+               rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
+                        f34->configuration_id);
+       }
+
+       return 0;
+}
+
+int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
+{
+       return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
+{
+       sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
+}
+
+struct rmi_function_handler rmi_f34_handler = {
+       .driver = {
+               .name = "rmi4_f34",
+       },
+       .func = 0x34,
+       .probe = rmi_f34_probe,
+       .attention = rmi_f34_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h
new file mode 100644 (file)
index 0000000..2c21056
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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 _RMI_F34_H
+#define _RMI_F34_H
+
+/* F34 image file offsets. */
+#define F34_FW_IMAGE_OFFSET    0x100
+
+/* F34 register offsets. */
+#define F34_BLOCK_DATA_OFFSET  2
+
+/* F34 commands */
+#define F34_WRITE_FW_BLOCK     0x2
+#define F34_ERASE_ALL          0x3
+#define F34_READ_CONFIG_BLOCK  0x5
+#define F34_WRITE_CONFIG_BLOCK 0x6
+#define F34_ERASE_CONFIG       0x7
+#define F34_ENABLE_FLASH_PROG  0xf
+
+#define F34_STATUS_IN_PROGRESS 0xff
+#define F34_STATUS_IDLE                0x80
+
+#define F34_IDLE_WAIT_MS       500
+#define F34_ENABLE_WAIT_MS     300
+#define F34_ERASE_WAIT_MS      5000
+
+#define F34_BOOTLOADER_ID_LEN  2
+
+/* F34 V7 defines */
+#define V7_FLASH_STATUS_OFFSET         0
+#define V7_PARTITION_ID_OFFSET         1
+#define V7_BLOCK_NUMBER_OFFSET         2
+#define V7_TRANSFER_LENGTH_OFFSET      3
+#define V7_COMMAND_OFFSET              4
+#define V7_PAYLOAD_OFFSET              5
+#define V7_BOOTLOADER_ID_OFFSET                1
+
+#define IMAGE_HEADER_VERSION_10                0x10
+
+#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)
+#define HAS_GUEST_CODE                 BIT(6)
+#define HAS_DISP_CFG                   BIT(5)
+
+/* F34 V7 commands */
+#define CMD_V7_IDLE                    0
+#define CMD_V7_ENTER_BL                        1
+#define CMD_V7_READ                    2
+#define CMD_V7_WRITE                   3
+#define CMD_V7_ERASE                   4
+#define CMD_V7_ERASE_AP                        5
+#define CMD_V7_SENSOR_ID               6
+
+#define v7_CMD_IDLE                    0
+#define v7_CMD_WRITE_FW                        1
+#define v7_CMD_WRITE_CONFIG            2
+#define v7_CMD_WRITE_LOCKDOWN          3
+#define v7_CMD_WRITE_GUEST_CODE                4
+#define v7_CMD_READ_CONFIG             5
+#define v7_CMD_ERASE_ALL               6
+#define v7_CMD_ERASE_UI_FIRMWARE       7
+#define v7_CMD_ERASE_UI_CONFIG         8
+#define v7_CMD_ERASE_BL_CONFIG         9
+#define v7_CMD_ERASE_DISP_CONFIG       10
+#define v7_CMD_ERASE_FLASH_CONFIG      11
+#define v7_CMD_ERASE_GUEST_CODE                12
+#define v7_CMD_ENABLE_FLASH_PROG       13
+
+#define v7_UI_CONFIG_AREA              0
+#define v7_PM_CONFIG_AREA              1
+#define v7_BL_CONFIG_AREA              2
+#define v7_DP_CONFIG_AREA              3
+#define v7_FLASH_CONFIG_AREA           4
+
+/* F34 V7 partition IDs */
+#define BOOTLOADER_PARTITION           1
+#define DEVICE_CONFIG_PARTITION                2
+#define FLASH_CONFIG_PARTITION         3
+#define MANUFACTURING_BLOCK_PARTITION  4
+#define GUEST_SERIALIZATION_PARTITION  5
+#define GLOBAL_PARAMETERS_PARTITION    6
+#define CORE_CODE_PARTITION            7
+#define CORE_CONFIG_PARTITION          8
+#define GUEST_CODE_PARTITION           9
+#define DISPLAY_CONFIG_PARTITION       10
+
+/* F34 V7 container IDs */
+#define TOP_LEVEL_CONTAINER                    0
+#define UI_CONTAINER                           1
+#define UI_CONFIG_CONTAINER                    2
+#define BL_CONTAINER                           3
+#define BL_IMAGE_CONTAINER                     4
+#define BL_CONFIG_CONTAINER                    5
+#define BL_LOCKDOWN_INFO_CONTAINER             6
+#define PERMANENT_CONFIG_CONTAINER             7
+#define GUEST_CODE_CONTAINER                   8
+#define BL_PROTOCOL_DESCRIPTOR_CONTAINER       9
+#define UI_PROTOCOL_DESCRIPTOR_CONTAINER       10
+#define RMI_SELF_DISCOVERY_CONTAINER           11
+#define RMI_PAGE_CONTENT_CONTAINER             12
+#define GENERAL_INFORMATION_CONTAINER          13
+#define DEVICE_CONFIG_CONTAINER                        14
+#define FLASH_CONFIG_CONTAINER                 15
+#define GUEST_SERIALIZATION_CONTAINER          16
+#define GLOBAL_PARAMETERS_CONTAINER            17
+#define CORE_CODE_CONTAINER                    18
+#define CORE_CONFIG_CONTAINER                  19
+#define DISPLAY_CONFIG_CONTAINER               20
+
+struct f34v7_query_1_7 {
+       u8 bl_minor_revision;                   /* query 1 */
+       u8 bl_major_revision;
+       __le32 bl_fw_id;                        /* query 2 */
+       u8 minimum_write_size;                  /* query 3 */
+       __le16 block_size;
+       __le16 flash_page_size;
+       __le16 adjustable_partition_area_size;  /* query 4 */
+       __le16 flash_config_length;             /* query 5 */
+       __le16 payload_length;                  /* query 6 */
+       u8 partition_support[4];                /* query 7 */
+} __packed;
+
+struct f34v7_data_1_5 {
+       u8 partition_id;
+       __le16 block_offset;
+       __le16 transfer_length;
+       u8 command;
+       u8 payload[2];
+} __packed;
+
+struct block_data {
+       const void *data;
+       int size;
+};
+
+struct partition_table {
+       u8 partition_id;
+       u8 byte_1_reserved;
+       __le16 partition_length;
+       __le16 start_physical_address;
+       __le16 partition_properties;
+} __packed;
+
+struct physical_address {
+       u16 ui_firmware;
+       u16 ui_config;
+       u16 dp_config;
+       u16 guest_code;
+};
+
+struct container_descriptor {
+       __le32 content_checksum;
+       __le16 container_id;
+       u8 minor_version;
+       u8 major_version;
+       u8 reserved_08;
+       u8 reserved_09;
+       u8 reserved_0a;
+       u8 reserved_0b;
+       u8 container_option_flags[4];
+       __le32 content_options_length;
+       __le32 content_options_address;
+       __le32 content_length;
+       __le32 content_address;
+} __packed;
+
+struct block_count {
+       u16 ui_firmware;
+       u16 ui_config;
+       u16 dp_config;
+       u16 fl_config;
+       u16 pm_config;
+       u16 bl_config;
+       u16 lockdown;
+       u16 guest_code;
+};
+
+struct image_header_10 {
+       __le32 checksum;
+       u8 reserved_04;
+       u8 reserved_05;
+       u8 minor_header_version;
+       u8 major_header_version;
+       u8 reserved_08;
+       u8 reserved_09;
+       u8 reserved_0a;
+       u8 reserved_0b;
+       __le32 top_level_container_start_addr;
+};
+
+struct image_metadata {
+       bool contains_firmware_id;
+       bool contains_bootloader;
+       bool contains_display_cfg;
+       bool contains_guest_code;
+       bool contains_flash_config;
+       unsigned int firmware_id;
+       unsigned int checksum;
+       unsigned int bootloader_size;
+       unsigned int display_cfg_offset;
+       unsigned char bl_version;
+       unsigned char product_id[PRODUCT_ID_SIZE + 1];
+       unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1];
+       struct block_data bootloader;
+       struct block_data ui_firmware;
+       struct block_data ui_config;
+       struct block_data dp_config;
+       struct block_data fl_config;
+       struct block_data bl_config;
+       struct block_data guest_code;
+       struct block_data lockdown;
+       struct block_count blkcount;
+       struct physical_address phyaddr;
+};
+
+struct register_offset {
+       u8 properties;
+       u8 properties_2;
+       u8 block_size;
+       u8 block_count;
+       u8 gc_block_count;
+       u8 flash_status;
+       u8 partition_id;
+       u8 block_number;
+       u8 transfer_length;
+       u8 flash_cmd;
+       u8 payload;
+};
+
+struct rmi_f34_firmware {
+       __le32 checksum;
+       u8 pad1[3];
+       u8 bootloader_version;
+       __le32 image_size;
+       __le32 config_size;
+       u8 product_id[10];
+       u8 product_info[2];
+       u8 pad2[228];
+       u8 data[];
+};
+
+struct f34v5_data {
+       u16 block_size;
+       u16 fw_blocks;
+       u16 config_blocks;
+       u16 ctrl_address;
+       u8 status;
+
+       struct completion cmd_done;
+       struct mutex flash_mutex;
+};
+
+struct f34v7_data {
+       bool has_display_cfg;
+       bool has_guest_code;
+       bool force_update;
+       bool in_bl_mode;
+       u8 *read_config_buf;
+       size_t read_config_buf_size;
+       u8 command;
+       u8 flash_status;
+       u16 block_size;
+       u16 config_block_count;
+       u16 config_size;
+       u16 config_area;
+       u16 flash_config_length;
+       u16 payload_length;
+       u8 partitions;
+       u16 partition_table_bytes;
+       bool new_partition_table;
+
+       struct register_offset off;
+       struct block_count blkcount;
+       struct physical_address phyaddr;
+       struct image_metadata img;
+
+       const void *config_data;
+       const void *image;
+};
+
+struct f34_data {
+       struct rmi_function *fn;
+
+       u8 bl_version;
+       unsigned char bootloader_id[5];
+       unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1];
+
+       union {
+               struct f34v5_data v5;
+               struct f34v7_data v7;
+       };
+};
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw);
+int rmi_f34v7_probe(struct f34_data *f34);
+
+#endif /* _RMI_F34_H */
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
new file mode 100644 (file)
index 0000000..ca31f95
--- /dev/null
@@ -0,0 +1,1372 @@
+/*
+ * Copyright (c) 2016, Zodiac Inflight Innovations
+ * Copyright (c) 2007-2016, Synaptics Incorporated
+ * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
+ * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.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/kernel.h>
+#include <linux/rmi.h>
+#include <linux/firmware.h>
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "rmi_driver.h"
+#include "rmi_f34.h"
+
+static int rmi_f34v7_read_flash_status(struct f34_data *f34)
+{
+       u8 status;
+       u8 command;
+       int ret;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.data_base_addr + f34->v7.off.flash_status,
+                       &status,
+                       sizeof(status));
+       if (ret < 0) {
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: Failed to read flash status\n", __func__);
+               return ret;
+       }
+
+       f34->v7.in_bl_mode = status >> 7;
+       f34->v7.flash_status = status & 0x1f;
+
+       if (f34->v7.flash_status != 0x00) {
+               dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n",
+                       __func__, f34->v7.flash_status, f34->v7.command);
+       }
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd,
+                       &command,
+                       sizeof(command));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read flash command\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->v7.command = command;
+
+       return 0;
+}
+
+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;
+
+       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);
+
+       dev_err(&f34->fn->dev,
+               "%s: Timed out waiting for idle status\n", __func__);
+
+       return -ETIMEDOUT;
+}
+
+static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34,
+                                                     u8 cmd)
+{
+       int ret;
+       u8 base;
+       struct f34v7_data_1_5 data_1_5;
+
+       base = f34->fn->fd.data_base_addr;
+
+       memset(&data_1_5, 0, sizeof(data_1_5));
+
+       switch (cmd) {
+       case v7_CMD_ERASE_ALL:
+               data_1_5.partition_id = CORE_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE_AP;
+               break;
+       case v7_CMD_ERASE_UI_FIRMWARE:
+               data_1_5.partition_id = CORE_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_BL_CONFIG:
+               data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_UI_CONFIG:
+               data_1_5.partition_id = CORE_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_DISP_CONFIG:
+               data_1_5.partition_id = DISPLAY_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_FLASH_CONFIG:
+               data_1_5.partition_id = FLASH_CONFIG_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ERASE_GUEST_CODE:
+               data_1_5.partition_id = GUEST_CODE_PARTITION;
+               data_1_5.command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               data_1_5.partition_id = BOOTLOADER_PARTITION;
+               data_1_5.command = CMD_V7_ENTER_BL;
+               break;
+       }
+
+       data_1_5.payload[0] = f34->bootloader_id[0];
+       data_1_5.payload[1] = f34->bootloader_id[1];
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.partition_id,
+                       &data_1_5, sizeof(data_1_5));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to write single transaction command\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd)
+{
+       int ret;
+       u8 base;
+       u8 command;
+
+       base = f34->fn->fd.data_base_addr;
+
+       switch (cmd) {
+       case v7_CMD_WRITE_FW:
+       case v7_CMD_WRITE_CONFIG:
+       case v7_CMD_WRITE_GUEST_CODE:
+               command = CMD_V7_WRITE;
+               break;
+       case v7_CMD_READ_CONFIG:
+               command = CMD_V7_READ;
+               break;
+       case v7_CMD_ERASE_ALL:
+               command = CMD_V7_ERASE_AP;
+               break;
+       case v7_CMD_ERASE_UI_FIRMWARE:
+       case v7_CMD_ERASE_BL_CONFIG:
+       case v7_CMD_ERASE_UI_CONFIG:
+       case v7_CMD_ERASE_DISP_CONFIG:
+       case v7_CMD_ERASE_FLASH_CONFIG:
+       case v7_CMD_ERASE_GUEST_CODE:
+               command = CMD_V7_ERASE;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               command = CMD_V7_ENTER_BL;
+               break;
+       default:
+               dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+                       __func__, cmd);
+               return -EINVAL;
+       }
+
+       f34->v7.command = command;
+
+       switch (cmd) {
+       case v7_CMD_ERASE_ALL:
+       case v7_CMD_ERASE_UI_FIRMWARE:
+       case v7_CMD_ERASE_BL_CONFIG:
+       case v7_CMD_ERASE_UI_CONFIG:
+       case v7_CMD_ERASE_DISP_CONFIG:
+       case v7_CMD_ERASE_FLASH_CONFIG:
+       case v7_CMD_ERASE_GUEST_CODE:
+       case v7_CMD_ENABLE_FLASH_PROG:
+               ret = rmi_f34v7_write_command_single_transaction(f34, cmd);
+               if (ret < 0)
+                       return ret;
+               else
+                       return 0;
+       default:
+               break;
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n",
+               __func__, command);
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.flash_cmd,
+                       &command, sizeof(command));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write flash command\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd)
+{
+       int ret;
+       u8 base;
+       u8 partition;
+
+       base = f34->fn->fd.data_base_addr;
+
+       switch (cmd) {
+       case v7_CMD_WRITE_FW:
+               partition = CORE_CODE_PARTITION;
+               break;
+       case v7_CMD_WRITE_CONFIG:
+       case v7_CMD_READ_CONFIG:
+               if (f34->v7.config_area == v7_UI_CONFIG_AREA)
+                       partition = CORE_CONFIG_PARTITION;
+               else if (f34->v7.config_area == v7_DP_CONFIG_AREA)
+                       partition = DISPLAY_CONFIG_PARTITION;
+               else if (f34->v7.config_area == v7_PM_CONFIG_AREA)
+                       partition = GUEST_SERIALIZATION_PARTITION;
+               else if (f34->v7.config_area == v7_BL_CONFIG_AREA)
+                       partition = GLOBAL_PARAMETERS_PARTITION;
+               else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA)
+                       partition = FLASH_CONFIG_PARTITION;
+               break;
+       case v7_CMD_WRITE_GUEST_CODE:
+               partition = GUEST_CODE_PARTITION;
+               break;
+       case v7_CMD_ERASE_ALL:
+               partition = CORE_CODE_PARTITION;
+               break;
+       case v7_CMD_ERASE_BL_CONFIG:
+               partition = GLOBAL_PARAMETERS_PARTITION;
+               break;
+       case v7_CMD_ERASE_UI_CONFIG:
+               partition = CORE_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_DISP_CONFIG:
+               partition = DISPLAY_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_FLASH_CONFIG:
+               partition = FLASH_CONFIG_PARTITION;
+               break;
+       case v7_CMD_ERASE_GUEST_CODE:
+               partition = GUEST_CODE_PARTITION;
+               break;
+       case v7_CMD_ENABLE_FLASH_PROG:
+               partition = BOOTLOADER_PARTITION;
+               break;
+       default:
+               dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n",
+                       __func__, cmd);
+               return -EINVAL;
+       }
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.partition_id,
+                       &partition, sizeof(partition));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 block_number = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+
+       ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       put_unaligned_le16(f34->v7.flash_config_length, &length);
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.transfer_length,
+                       &length, sizeof(length));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n",
+                       __func__);
+               return ret;
+       }
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write command\n",
+                       __func__);
+               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;
+       }
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.payload,
+                       f34->v7.read_config_buf,
+                       f34->v7.partition_table_bytes);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read block data\n",
+                       __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void rmi_f34v7_parse_partition_table(struct f34_data *f34,
+                                           const void *partition_table,
+                                           struct block_count *blkcount,
+                                           struct physical_address *phyaddr)
+{
+       int i;
+       int index;
+       u16 partition_length;
+       u16 physical_address;
+       const struct partition_table *ptable;
+
+       for (i = 0; i < f34->v7.partitions; i++) {
+               index = i * 8 + 2;
+               ptable = partition_table + index;
+               partition_length = le16_to_cpu(ptable->partition_length);
+               physical_address = le16_to_cpu(ptable->start_physical_address);
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: Partition entry %d: %*ph\n",
+                       __func__, i, sizeof(struct partition_table), ptable);
+               switch (ptable->partition_id & 0x1f) {
+               case CORE_CODE_PARTITION:
+                       blkcount->ui_firmware = partition_length;
+                       phyaddr->ui_firmware = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Core code block count: %d\n",
+                               __func__, blkcount->ui_firmware);
+                       break;
+               case CORE_CONFIG_PARTITION:
+                       blkcount->ui_config = partition_length;
+                       phyaddr->ui_config = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Core config block count: %d\n",
+                               __func__, blkcount->ui_config);
+                       break;
+               case DISPLAY_CONFIG_PARTITION:
+                       blkcount->dp_config = partition_length;
+                       phyaddr->dp_config = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Display config block count: %d\n",
+                               __func__, blkcount->dp_config);
+                       break;
+               case FLASH_CONFIG_PARTITION:
+                       blkcount->fl_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Flash config block count: %d\n",
+                               __func__, blkcount->fl_config);
+                       break;
+               case GUEST_CODE_PARTITION:
+                       blkcount->guest_code = partition_length;
+                       phyaddr->guest_code = physical_address;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Guest code block count: %d\n",
+                               __func__, blkcount->guest_code);
+                       break;
+               case GUEST_SERIALIZATION_PARTITION:
+                       blkcount->pm_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Guest serialization block count: %d\n",
+                               __func__, blkcount->pm_config);
+                       break;
+               case GLOBAL_PARAMETERS_PARTITION:
+                       blkcount->bl_config = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Global parameters block count: %d\n",
+                               __func__, blkcount->bl_config);
+                       break;
+               case DEVICE_CONFIG_PARTITION:
+                       blkcount->lockdown = partition_length;
+                       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                               "%s: Device config block count: %d\n",
+                               __func__, blkcount->lockdown);
+                       break;
+               }
+       }
+}
+
+static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34)
+{
+       int ret;
+       u8 base;
+       int offset;
+       u8 query_0;
+       struct f34v7_query_1_7 query_1_7;
+
+       base = f34->fn->fd.query_base_addr;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base,
+                       &query_0,
+                       sizeof(query_0));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read query 0\n", __func__);
+               return ret;
+       }
+
+       offset = (query_0 & 0x7) + 1;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + offset,
+                       &query_1_7,
+                       sizeof(query_1_7));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+       f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n",
+               f34->bootloader_id[1], f34->bootloader_id[0]);
+
+       return 0;
+}
+
+static int rmi_f34v7_read_queries(struct f34_data *f34)
+{
+       int ret;
+       int i, j;
+       u8 base;
+       int offset;
+       u8 *ptable;
+       u8 query_0;
+       struct f34v7_query_1_7 query_1_7;
+
+       base = f34->fn->fd.query_base_addr;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base,
+                       &query_0,
+                       sizeof(query_0));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev,
+                       "%s: Failed to read query 0\n", __func__);
+               return ret;
+       }
+
+       offset = (query_0 & 0x07) + 1;
+
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       base + offset,
+                       &query_1_7,
+                       sizeof(query_1_7));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n",
+                       __func__);
+               return ret;
+       }
+
+       f34->bootloader_id[0] = query_1_7.bl_minor_revision;
+       f34->bootloader_id[1] = query_1_7.bl_major_revision;
+
+       f34->v7.block_size = le16_to_cpu(query_1_7.block_size);
+       f34->v7.flash_config_length =
+                       le16_to_cpu(query_1_7.flash_config_length);
+       f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n",
+                __func__, f34->v7.block_size);
+
+       f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET;
+       f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET;
+       f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET;
+       f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET;
+       f34->v7.off.flash_cmd = V7_COMMAND_OFFSET;
+       f34->v7.off.payload = V7_PAYLOAD_OFFSET;
+
+       f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG;
+       f34->v7.has_guest_code =
+                       query_1_7.partition_support[1] & HAS_GUEST_CODE;
+
+       if (query_0 & HAS_CONFIG_ID) {
+               char f34_ctrl[CONFIG_ID_SIZE];
+               int i = 0;
+               u8 *p = f34->configuration_id;
+               *p = '\0';
+
+               ret = rmi_read_block(f34->fn->rmi_dev,
+                               f34->fn->fd.control_base_addr,
+                               f34_ctrl,
+                               sizeof(f34_ctrl));
+               if (ret)
+                       return ret;
+
+               /* Eat leading zeros */
+               while (i < sizeof(f34_ctrl) && !f34_ctrl[i])
+                       i++;
+
+               for (; i < sizeof(f34_ctrl); i++)
+                       p += snprintf(p, f34->configuration_id
+                                     + sizeof(f34->configuration_id) - p,
+                                     "%02X", f34_ctrl[i]);
+
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n",
+                       f34->configuration_id);
+       }
+
+       f34->v7.partitions = 0;
+       for (i = 0; i < sizeof(query_1_7.partition_support); i++)
+               for (j = 0; j < 8; j++)
+                       if (query_1_7.partition_support[i] & (1 << j))
+                               f34->v7.partitions++;
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n",
+               __func__, sizeof(query_1_7.partition_support),
+               query_1_7.partition_support);
+
+
+       f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2;
+
+       f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+                       f34->v7.partition_table_bytes,
+                       GFP_KERNEL);
+       if (!f34->v7.read_config_buf) {
+               f34->v7.read_config_buf_size = 0;
+               return -ENOMEM;
+       }
+
+       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);
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read partition table\n",
+                               __func__);
+               return ret;
+       }
+
+       rmi_f34v7_parse_partition_table(f34, ptable,
+                                       &f34->v7.blkcount, &f34->v7.phyaddr);
+
+       return 0;
+}
+
+static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.ui_firmware) {
+               dev_err(&f34->fn->dev,
+                       "UI firmware size mismatch: %d != %d\n",
+                       block_count, f34->v7.blkcount.ui_firmware);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_ui_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.ui_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.ui_config) {
+               dev_err(&f34->fn->dev, "UI config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_dp_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.dp_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.dp_config) {
+               dev_err(&f34->fn->dev, "Display config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_guest_code_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.guest_code.size / f34->v7.block_size;
+       if (block_count != f34->v7.blkcount.guest_code) {
+               dev_err(&f34->fn->dev, "Guest code size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_check_bl_config_size(struct f34_data *f34)
+{
+       u16 block_count;
+
+       block_count = f34->v7.img.bl_config.size / f34->v7.block_size;
+
+       if (block_count != f34->v7.blkcount.bl_config) {
+               dev_err(&f34->fn->dev, "Bootloader config size mismatch\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_erase_config(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing config...\n");
+
+       switch (f34->v7.config_area) {
+       case v7_UI_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       case v7_DP_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       case v7_BL_CONFIG_AREA:
+               ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG);
+               if (ret < 0)
+                       return ret;
+               break;
+       }
+
+       ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int rmi_f34v7_erase_guest_code(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing guest code...\n");
+
+       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);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_erase_all(struct f34_data *f34)
+{
+       int ret;
+
+       dev_info(&f34->fn->dev, "Erasing firmware...\n");
+
+       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);
+       if (ret < 0)
+               return ret;
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       ret = rmi_f34v7_erase_config(f34);
+       if (ret < 0)
+               return ret;
+
+       if (f34->v7.has_display_cfg) {
+               f34->v7.config_area = v7_DP_CONFIG_AREA;
+               ret = rmi_f34v7_erase_config(f34);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (f34->v7.new_partition_table && f34->v7.has_guest_code) {
+               ret = rmi_f34v7_erase_guest_code(f34);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt,
+                                      u8 command)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 transfer;
+       u16 max_transfer;
+       u16 remaining = block_cnt;
+       u16 block_number = 0;
+       u16 index = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       ret = rmi_f34v7_write_partition_id(f34, command);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       max_transfer = min(f34->v7.payload_length,
+                          (u16)(PAGE_SIZE / f34->v7.block_size));
+
+       do {
+               transfer = min(remaining, max_transfer);
+               put_unaligned_le16(transfer, &length);
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.transfer_length,
+                               &length, sizeof(length));
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Write transfer length fail (%d remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               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);
+                       return ret;
+               }
+
+               ret = rmi_read_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.payload,
+                               &f34->v7.read_config_buf[index],
+                               transfer * f34->v7.block_size);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Read block failed (%d blks remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               index += (transfer * f34->v7.block_size);
+               remaining -= transfer;
+       } while (remaining);
+
+       return 0;
+}
+
+static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34,
+                                       const void *block_ptr, u16 block_cnt,
+                                       u8 command)
+{
+       int ret;
+       u8 base;
+       __le16 length;
+       u16 transfer;
+       u16 max_transfer;
+       u16 remaining = block_cnt;
+       u16 block_number = 0;
+
+       base = f34->fn->fd.data_base_addr;
+
+       ret = rmi_f34v7_write_partition_id(f34, command);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_write_block(f34->fn->rmi_dev,
+                       base + f34->v7.off.block_number,
+                       &block_number, sizeof(block_number));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to write block number\n",
+                       __func__);
+               return ret;
+       }
+
+       if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size))
+               max_transfer = PAGE_SIZE / f34->v7.block_size;
+       else
+               max_transfer = f34->v7.payload_length;
+
+       do {
+               transfer = min(remaining, max_transfer);
+               put_unaligned_le16(transfer, &length);
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.transfer_length,
+                               &length, sizeof(length));
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Write transfer length fail (%d remaining)\n",
+                               __func__, remaining);
+                       return ret;
+               }
+
+               ret = rmi_f34v7_write_command(f34, command);
+               if (ret < 0)
+                       return ret;
+
+               ret = rmi_write_block(f34->fn->rmi_dev,
+                               base + f34->v7.off.payload,
+                               block_ptr, transfer * f34->v7.block_size);
+               if (ret < 0) {
+                       dev_err(&f34->fn->dev,
+                               "%s: Failed writing data (%d blks remaining)\n",
+                               __func__, remaining);
+                       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);
+                       return ret;
+               }
+
+               block_ptr += (transfer * f34->v7.block_size);
+               remaining -= transfer;
+       } while (remaining);
+
+       return 0;
+}
+
+static int rmi_f34v7_write_config(struct f34_data *f34)
+{
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data,
+                                           f34->v7.config_block_count,
+                                           v7_CMD_WRITE_CONFIG);
+}
+
+static int rmi_f34v7_write_ui_config(struct f34_data *f34)
+{
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.ui_config.data;
+       f34->v7.config_size = f34->v7.img.ui_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_dp_config(struct f34_data *f34)
+{
+       f34->v7.config_area = v7_DP_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.dp_config.data;
+       f34->v7.config_size = f34->v7.img.dp_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       return rmi_f34v7_write_config(f34);
+}
+
+static int rmi_f34v7_write_guest_code(struct f34_data *f34)
+{
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data,
+                                           f34->v7.img.guest_code.size /
+                                                       f34->v7.block_size,
+                                           v7_CMD_WRITE_GUEST_CODE);
+}
+
+static int rmi_f34v7_write_flash_config(struct f34_data *f34)
+{
+       int ret;
+
+       f34->v7.config_area = v7_FLASH_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.img.fl_config.data;
+       f34->v7.config_size = f34->v7.img.fl_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) {
+               dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       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);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_write_config(f34);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_write_partition_table(struct f34_data *f34)
+{
+       u16 block_count;
+       int ret;
+
+       block_count = f34->v7.blkcount.bl_config;
+       f34->v7.config_area = v7_BL_CONFIG_AREA;
+       f34->v7.config_size = f34->v7.block_size * block_count;
+       devm_kfree(&f34->fn->dev, f34->v7.read_config_buf);
+       f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev,
+                                              f34->v7.config_size, GFP_KERNEL);
+       if (!f34->v7.read_config_buf) {
+               f34->v7.read_config_buf_size = 0;
+               return -ENOMEM;
+       }
+
+       f34->v7.read_config_buf_size = f34->v7.config_size;
+
+       ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_erase_config(f34);
+       if (ret < 0)
+               return ret;
+
+       ret = rmi_f34v7_write_flash_config(f34);
+       if (ret < 0)
+               return ret;
+
+       f34->v7.config_area = v7_BL_CONFIG_AREA;
+       f34->v7.config_data = f34->v7.read_config_buf;
+       f34->v7.config_size = f34->v7.img.bl_config.size;
+       f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size;
+
+       ret = rmi_f34v7_write_config(f34);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int rmi_f34v7_write_firmware(struct f34_data *f34)
+{
+       u16 blk_count;
+
+       blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size;
+
+       return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data,
+                                           blk_count, v7_CMD_WRITE_FW);
+}
+
+static void rmi_f34v7_compare_partition_tables(struct f34_data *f34)
+{
+       if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.has_display_cfg &&
+           f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       if (f34->v7.has_guest_code &&
+           f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) {
+               f34->v7.new_partition_table = true;
+               return;
+       }
+
+       f34->v7.new_partition_table = false;
+}
+
+static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34,
+                                                      const void *image)
+{
+       int i;
+       int num_of_containers;
+       unsigned int addr;
+       unsigned int container_id;
+       unsigned int length;
+       const void *content;
+       const struct container_descriptor *descriptor;
+
+       num_of_containers = f34->v7.img.bootloader.size / 4 - 1;
+
+       for (i = 1; i <= num_of_containers; i++) {
+               addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4);
+               descriptor = image + addr;
+               container_id = le16_to_cpu(descriptor->container_id);
+               content = image + le32_to_cpu(descriptor->content_address);
+               length = le32_to_cpu(descriptor->content_length);
+               switch (container_id) {
+               case BL_CONFIG_CONTAINER:
+               case GLOBAL_PARAMETERS_CONTAINER:
+                       f34->v7.img.bl_config.data = content;
+                       f34->v7.img.bl_config.size = length;
+                       break;
+               case BL_LOCKDOWN_INFO_CONTAINER:
+               case DEVICE_CONFIG_CONTAINER:
+                       f34->v7.img.lockdown.data = content;
+                       f34->v7.img.lockdown.size = length;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void rmi_f34v7_parse_image_header_10(struct f34_data *f34)
+{
+       unsigned int i;
+       unsigned int num_of_containers;
+       unsigned int addr;
+       unsigned int offset;
+       unsigned int container_id;
+       unsigned int length;
+       const void *image = f34->v7.image;
+       const u8 *content;
+       const struct container_descriptor *descriptor;
+       const struct image_header_10 *header = image;
+
+       f34->v7.img.checksum = le32_to_cpu(header->checksum);
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n",
+               __func__, f34->v7.img.checksum);
+
+       /* address of top level container */
+       offset = le32_to_cpu(header->top_level_container_start_addr);
+       descriptor = image + offset;
+
+       /* address of top level container content */
+       offset = le32_to_cpu(descriptor->content_address);
+       num_of_containers = le32_to_cpu(descriptor->content_length) / 4;
+
+       for (i = 0; i < num_of_containers; i++) {
+               addr = get_unaligned_le32(image + offset);
+               offset += 4;
+               descriptor = image + addr;
+               container_id = le16_to_cpu(descriptor->container_id);
+               content = image + le32_to_cpu(descriptor->content_address);
+               length = le32_to_cpu(descriptor->content_length);
+
+               rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+                       "%s: container_id=%d, length=%d\n", __func__,
+                       container_id, length);
+
+               switch (container_id) {
+               case UI_CONTAINER:
+               case CORE_CODE_CONTAINER:
+                       f34->v7.img.ui_firmware.data = content;
+                       f34->v7.img.ui_firmware.size = length;
+                       break;
+               case UI_CONFIG_CONTAINER:
+               case CORE_CONFIG_CONTAINER:
+                       f34->v7.img.ui_config.data = content;
+                       f34->v7.img.ui_config.size = length;
+                       break;
+               case BL_CONTAINER:
+                       f34->v7.img.bl_version = *content;
+                       f34->v7.img.bootloader.data = content;
+                       f34->v7.img.bootloader.size = length;
+                       rmi_f34v7_parse_img_header_10_bl_container(f34, image);
+                       break;
+               case GUEST_CODE_CONTAINER:
+                       f34->v7.img.contains_guest_code = true;
+                       f34->v7.img.guest_code.data = content;
+                       f34->v7.img.guest_code.size = length;
+                       break;
+               case DISPLAY_CONFIG_CONTAINER:
+                       f34->v7.img.contains_display_cfg = true;
+                       f34->v7.img.dp_config.data = content;
+                       f34->v7.img.dp_config.size = length;
+                       break;
+               case FLASH_CONFIG_CONTAINER:
+                       f34->v7.img.contains_flash_config = true;
+                       f34->v7.img.fl_config.data = content;
+                       f34->v7.img.fl_config.size = length;
+                       break;
+               case GENERAL_INFORMATION_CONTAINER:
+                       f34->v7.img.contains_firmware_id = true;
+                       f34->v7.img.firmware_id =
+                               get_unaligned_le32(content + 4);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static int rmi_f34v7_parse_image_info(struct f34_data *f34)
+{
+       const struct image_header_10 *header = f34->v7.image;
+
+       memset(&f34->v7.img, 0x00, sizeof(f34->v7.img));
+
+       rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev,
+               "%s: header->major_header_version = %d\n",
+               __func__, header->major_header_version);
+
+       switch (header->major_header_version) {
+       case IMAGE_HEADER_VERSION_10:
+               rmi_f34v7_parse_image_header_10(f34);
+               break;
+       default:
+               dev_err(&f34->fn->dev, "Unsupported image file format %02X\n",
+                       header->major_header_version);
+               return -EINVAL;
+       }
+
+       if (!f34->v7.img.contains_flash_config) {
+               dev_err(&f34->fn->dev, "%s: No flash config in fw image\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data,
+                       &f34->v7.img.blkcount, &f34->v7.img.phyaddr);
+
+       rmi_f34v7_compare_partition_tables(f34);
+
+       return 0;
+}
+
+int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+       int ret;
+
+       rmi_f34v7_read_queries_bl_version(f34);
+
+       f34->v7.image = fw->data;
+
+       ret = rmi_f34v7_parse_image_info(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (!f34->v7.new_partition_table) {
+               ret = rmi_f34v7_check_ui_firmware_size(f34);
+               if (ret < 0)
+                       goto fail;
+
+               ret = rmi_f34v7_check_ui_config_size(f34);
+               if (ret < 0)
+                       goto fail;
+
+               if (f34->v7.has_display_cfg &&
+                   f34->v7.img.contains_display_cfg) {
+                       ret = rmi_f34v7_check_dp_config_size(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+
+               if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+                       ret = rmi_f34v7_check_guest_code_size(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+       } else {
+               ret = rmi_f34v7_check_bl_config_size(f34);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       ret = rmi_f34v7_erase_all(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (f34->v7.new_partition_table) {
+               ret = rmi_f34v7_write_partition_table(f34);
+               if (ret < 0)
+                       goto fail;
+               dev_info(&f34->fn->dev, "%s: Partition table programmed\n",
+                        __func__);
+       }
+
+       dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n",
+                f34->v7.img.ui_firmware.size);
+
+       ret = rmi_f34v7_write_firmware(f34);
+       if (ret < 0)
+               goto fail;
+
+       dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n",
+                f34->v7.img.ui_config.size);
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       ret = rmi_f34v7_write_ui_config(f34);
+       if (ret < 0)
+               goto fail;
+
+       if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) {
+               dev_info(&f34->fn->dev, "Writing display config...\n");
+
+               ret = rmi_f34v7_write_dp_config(f34);
+               if (ret < 0)
+                       goto fail;
+       }
+
+       if (f34->v7.new_partition_table) {
+               if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) {
+                       dev_info(&f34->fn->dev, "Writing guest code...\n");
+
+                       ret = rmi_f34v7_write_guest_code(f34);
+                       if (ret < 0)
+                               goto fail;
+               }
+       }
+
+fail:
+       return ret;
+}
+
+static int rmi_f34v7_enter_flash_prog(struct f34_data *f34)
+{
+       int ret;
+
+       ret = rmi_f34v7_read_flash_status(f34);
+       if (ret < 0)
+               return ret;
+
+       if (f34->v7.in_bl_mode)
+               return 0;
+
+       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);
+       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;
+}
+
+int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw)
+{
+       int ret = 0;
+
+       f34->v7.config_area = v7_UI_CONFIG_AREA;
+       f34->v7.image = fw->data;
+
+       ret = rmi_f34v7_parse_image_info(f34);
+       if (ret < 0)
+               goto exit;
+
+       if (!f34->v7.force_update && f34->v7.new_partition_table) {
+               dev_err(&f34->fn->dev, "%s: Partition table mismatch\n",
+                               __func__);
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       dev_info(&f34->fn->dev, "Firmware image OK\n");
+
+       ret = rmi_f34v7_read_flash_status(f34);
+       if (ret < 0)
+               goto exit;
+
+       if (f34->v7.in_bl_mode) {
+               dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n",
+                               __func__);
+       }
+
+       rmi_f34v7_enter_flash_prog(f34);
+
+       return 0;
+
+exit:
+       return ret;
+}
+
+int rmi_f34v7_probe(struct f34_data *f34)
+{
+       int ret;
+
+       /* Read bootloader version */
+       ret = rmi_read_block(f34->fn->rmi_dev,
+                       f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET,
+                       f34->bootloader_id,
+                       sizeof(f34->bootloader_id));
+       if (ret < 0) {
+               dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n",
+                       __func__);
+               return ret;
+       }
+
+       if (f34->bootloader_id[1] == '5') {
+               f34->bl_version = 5;
+       } else if (f34->bootloader_id[1] == '6') {
+               f34->bl_version = 6;
+       } else if (f34->bootloader_id[1] == 7) {
+               f34->bl_version = 7;
+       } else {
+               dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       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;
+       return 0;
+}
index cf805b960866215f52e96b2ae9a21ae373ddedfb..dea63e2db3e6213f5e83d6067870a16cc5707e6d 100644 (file)
@@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
 
        error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT);
        if (error < 0)
-               return error;
+               goto unlock;
 
        init_completion(&f54->cmd_done);
 
@@ -209,15 +209,18 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type)
 
        queue_delayed_work(f54->workqueue, &f54->work, 0);
 
+unlock:
        mutex_unlock(&f54->data_mutex);
 
-       return 0;
+       return error;
 }
 
 static size_t rmi_f54_get_report_size(struct f54_data *f54)
 {
-       u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes;
-       u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes;
+       struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+       u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
        size_t size;
 
        switch (rmi_f54_get_reptype(f54, f54->input)) {
@@ -401,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv,
 
 static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
 {
+       struct rmi_device *rmi_dev = f54->fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes;
+       u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes;
        struct v4l2_pix_format *f = &f54->format;
        enum rmi_f54_report_type reptype;
        int ret;
@@ -415,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i)
 
        f54->input = i;
 
-       f->width = f54->num_rx_electrodes;
-       f->height = f54->num_tx_electrodes;
+       f->width = rx;
+       f->height = tx;
        f->field = V4L2_FIELD_NONE;
        f->colorspace = V4L2_COLORSPACE_RAW;
        f->bytesperline = f->width * sizeof(u16);
diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c
new file mode 100644 (file)
index 0000000..37390ca
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012-2015 Synaptics Incorporated
+ * Copyright (C) 2016 Zodiac Inflight Innovations
+ *
+ * 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/bitops.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define F55_NAME               "rmi4_f55"
+
+/* F55 data offsets */
+#define F55_NUM_RX_OFFSET      0
+#define F55_NUM_TX_OFFSET      1
+#define F55_PHYS_CHAR_OFFSET   2
+
+/* Only read required query registers */
+#define F55_QUERY_LEN          3
+
+/* F55 capabilities */
+#define F55_CAP_SENSOR_ASSIGN  BIT(0)
+
+struct f55_data {
+       struct rmi_function *fn;
+
+       u8 qry[F55_QUERY_LEN];
+       u8 num_rx_electrodes;
+       u8 cfg_num_rx_electrodes;
+       u8 num_tx_electrodes;
+       u8 cfg_num_tx_electrodes;
+};
+
+static int rmi_f55_detect(struct rmi_function *fn)
+{
+       struct rmi_device *rmi_dev = fn->rmi_dev;
+       struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+       struct f55_data *f55;
+       int error;
+
+       f55 = dev_get_drvdata(&fn->dev);
+
+       error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+                              &f55->qry, sizeof(f55->qry));
+       if (error) {
+               dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
+                       __func__);
+               return error;
+       }
+
+       f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
+       f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
+
+       f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
+       f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
+
+       drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
+       drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
+
+       if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
+               int i, total;
+               u8 buf[256];
+
+               /*
+                * Calculate the number of enabled receive and transmit
+                * electrodes by reading F55:Ctrl1 (sensor receiver assignment)
+                * and F55:Ctrl2 (sensor transmitter assignment). The number of
+                * enabled electrodes is the sum of all field entries with a
+                * value other than 0xff.
+                */
+               error = rmi_read_block(fn->rmi_dev,
+                                      fn->fd.control_base_addr + 1,
+                                      buf, f55->num_rx_electrodes);
+               if (!error) {
+                       total = 0;
+                       for (i = 0; i < f55->num_rx_electrodes; i++) {
+                               if (buf[i] != 0xff)
+                                       total++;
+                       }
+                       f55->cfg_num_rx_electrodes = total;
+                       drv_data->num_rx_electrodes = total;
+               }
+
+               error = rmi_read_block(fn->rmi_dev,
+                                      fn->fd.control_base_addr + 2,
+                                      buf, f55->num_tx_electrodes);
+               if (!error) {
+                       total = 0;
+                       for (i = 0; i < f55->num_tx_electrodes; i++) {
+                               if (buf[i] != 0xff)
+                                       total++;
+                       }
+                       f55->cfg_num_tx_electrodes = total;
+                       drv_data->num_tx_electrodes = total;
+               }
+       }
+
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
+               f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
+       rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
+               f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
+
+       return 0;
+}
+
+static int rmi_f55_probe(struct rmi_function *fn)
+{
+       struct f55_data *f55;
+
+       f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
+       if (!f55)
+               return -ENOMEM;
+
+       f55->fn = fn;
+       dev_set_drvdata(&fn->dev, f55);
+
+       return rmi_f55_detect(fn);
+}
+
+struct rmi_function_handler rmi_f55_handler = {
+       .driver = {
+               .name = F55_NAME,
+       },
+       .func = 0x55,
+       .probe = rmi_f55_probe,
+};
index 1ebc2c1debae31e5d1479466085a9d7fbcfc586f..082306d7c207993c71a898a4dd17583a55ba8b4d 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/i2c.h>
 #include <linux/rmi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
@@ -35,8 +34,6 @@ struct rmi_i2c_xport {
        struct mutex page_mutex;
        int page;
 
-       int irq;
-
        u8 *tx_buf;
        size_t tx_buf_size;
 
@@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = {
        .read_block     = rmi_i2c_read_block,
 };
 
-static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
-{
-       struct rmi_i2c_xport *rmi_i2c = dev_id;
-       struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
-       int ret;
-
-       ret = rmi_process_interrupt_requests(rmi_dev);
-       if (ret)
-               rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-                       "Failed to process interrupt request: %d\n", ret);
-
-       return IRQ_HANDLED;
-}
-
-static int rmi_i2c_init_irq(struct i2c_client *client)
-{
-       struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
-       int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
-       int ret;
-
-       if (!irq_flags)
-               irq_flags = IRQF_TRIGGER_LOW;
-
-       ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
-                       rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
-                       rmi_i2c);
-       if (ret < 0) {
-               dev_warn(&client->dev, "Failed to register interrupt %d\n",
-                       rmi_i2c->irq);
-
-               return ret;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static const struct of_device_id rmi_i2c_of_match[] = {
        { .compatible = "syna,rmi4-i2c" },
@@ -255,8 +216,7 @@ static int rmi_i2c_probe(struct i2c_client *client,
        if (!client->dev.of_node && client_pdata)
                *pdata = *client_pdata;
 
-       if (client->irq > 0)
-               rmi_i2c->irq = client->irq;
+       pdata->irq = client->irq;
 
        rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
                        dev_name(&client->dev));
@@ -321,10 +281,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
        if (retval)
                return retval;
 
-       retval = rmi_i2c_init_irq(client);
-       if (retval < 0)
-               return retval;
-
        dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
                        client->addr);
        return 0;
@@ -337,18 +293,10 @@ static int rmi_i2c_suspend(struct device *dev)
        struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_i2c->irq);
-       if (device_may_wakeup(&client->dev)) {
-               ret = enable_irq_wake(rmi_i2c->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to enable irq for wake: %d\n",
-                               ret);
-       }
-
        regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
                               rmi_i2c->supplies);
 
@@ -368,15 +316,7 @@ static int rmi_i2c_resume(struct device *dev)
 
        msleep(rmi_i2c->startup_delay);
 
-       enable_irq(rmi_i2c->irq);
-       if (device_may_wakeup(&client->dev)) {
-               ret = disable_irq_wake(rmi_i2c->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to disable irq for wake: %d\n",
-                               ret);
-       }
-
-       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -391,12 +331,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev)
        struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_i2c->irq);
-
        regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
                               rmi_i2c->supplies);
 
@@ -416,9 +354,7 @@ static int rmi_i2c_runtime_resume(struct device *dev)
 
        msleep(rmi_i2c->startup_delay);
 
-       enable_irq(rmi_i2c->irq);
-
-       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c
new file mode 100644 (file)
index 0000000..7675255
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2015 - 2016 Red Hat, Inc
+ * Copyright (c) 2011, 2012 Synaptics Incorporated
+ * Copyright (c) 2011 Unixphere
+ *
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kconfig.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/rmi.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define SMB_PROTOCOL_VERSION_ADDRESS   0xfd
+#define SMB_MAX_COUNT                  32
+#define RMI_SMB2_MAP_SIZE              8 /* 8 entry of 4 bytes each */
+#define RMI_SMB2_MAP_FLAGS_WE          0x01
+
+struct mapping_table_entry {
+       __le16 rmiaddr;
+       u8 readcount;
+       u8 flags;
+};
+
+struct rmi_smb_xport {
+       struct rmi_transport_dev xport;
+       struct i2c_client *client;
+
+       struct mutex page_mutex;
+       int page;
+       u8 table_index;
+       struct mutex mappingtable_mutex;
+       struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
+};
+
+static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
+{
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       /* Check if for SMBus new version device by reading version byte. */
+       retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
+       if (retval < 0) {
+               dev_err(&client->dev, "failed to get SMBus version number!\n");
+               return retval;
+       }
+       return retval + 1;
+}
+
+/* SMB block write - wrapper over ic2_smb_write_block */
+static int smb_block_write(struct rmi_transport_dev *xport,
+                             u8 commandcode, const void *buf, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
+
+       rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
+               "wrote %zd bytes at %#04x: %d (%*ph)\n",
+               len, commandcode, retval, (int)len, buf);
+
+       return retval;
+}
+
+/*
+ * The function to get command code for smbus operations and keeps
+ * records to the driver mapping table
+ */
+static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
+               u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int i;
+       int retval;
+       struct mapping_table_entry mapping_data[1];
+
+       mutex_lock(&rmi_smb->mappingtable_mutex);
+       for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
+               if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) {
+                       if (isread) {
+                               if (rmi_smb->mapping_table[i].readcount
+                                                       == bytecount) {
+                                       *commandcode = i;
+                                       retval = 0;
+                                       goto exit;
+                               }
+                       } else {
+                               if (rmi_smb->mapping_table[i].flags &
+                                                       RMI_SMB2_MAP_FLAGS_WE) {
+                                       *commandcode = i;
+                                       retval = 0;
+                                       goto exit;
+                               }
+                       }
+               }
+       }
+       i = rmi_smb->table_index;
+       rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
+
+       /* constructs mapping table data entry. 4 bytes each entry */
+       memset(mapping_data, 0, sizeof(mapping_data));
+
+       mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
+       mapping_data[0].readcount = bytecount;
+       mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
+
+       retval = smb_block_write(xport, i + 0x80, mapping_data,
+                                sizeof(mapping_data));
+
+       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;
+       }
+       /* 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;
+
+exit:
+       mutex_unlock(&rmi_smb->mappingtable_mutex);
+
+       return retval;
+}
+
+static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+                               const void *databuff, size_t len)
+{
+       int retval = 0;
+       u8 commandcode;
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int cur_len = (int)len;
+
+       mutex_lock(&rmi_smb->page_mutex);
+
+       while (cur_len > 0) {
+               /*
+                * break into 32 bytes chunks to write get command code
+                */
+               int block_len = min_t(int, len, SMB_MAX_COUNT);
+
+               retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+                                                 false, &commandcode);
+               if (retval < 0)
+                       goto exit;
+
+               retval = smb_block_write(xport, commandcode,
+                                        databuff, block_len);
+               if (retval < 0)
+                       goto exit;
+
+               /* prepare to write next block of bytes */
+               cur_len -= SMB_MAX_COUNT;
+               databuff += SMB_MAX_COUNT;
+               rmiaddr += SMB_MAX_COUNT;
+       }
+exit:
+       mutex_unlock(&rmi_smb->page_mutex);
+       return retval;
+}
+
+/* SMB block read - wrapper over ic2_smb_read_block */
+static int smb_block_read(struct rmi_transport_dev *xport,
+                            u8 commandcode, void *buf, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       struct i2c_client *client = rmi_smb->client;
+       int retval;
+
+       retval = i2c_smbus_read_block_data(client, commandcode, buf);
+       if (retval < 0)
+               return retval;
+
+       return retval;
+}
+
+static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
+                             void *databuff, size_t len)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+       int retval;
+       u8 commandcode;
+       int cur_len = (int)len;
+
+       mutex_lock(&rmi_smb->page_mutex);
+       memset(databuff, 0, len);
+
+       while (cur_len > 0) {
+               /* break into 32 bytes chunks to write get command code */
+               int block_len =  min_t(int, cur_len, SMB_MAX_COUNT);
+
+               retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
+                                                 true, &commandcode);
+               if (retval < 0)
+                       goto exit;
+
+               retval = smb_block_read(xport, commandcode,
+                                       databuff, block_len);
+               if (retval < 0)
+                       goto exit;
+
+               /* prepare to read next block of bytes */
+               cur_len -= SMB_MAX_COUNT;
+               databuff += SMB_MAX_COUNT;
+               rmiaddr += SMB_MAX_COUNT;
+       }
+
+       retval = 0;
+
+exit:
+       mutex_unlock(&rmi_smb->page_mutex);
+       return retval;
+}
+
+static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
+{
+       /* the mapping table has been flushed, discard the current one */
+       mutex_lock(&rmi_smb->mappingtable_mutex);
+       memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
+       mutex_unlock(&rmi_smb->mappingtable_mutex);
+}
+
+static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
+{
+       int retval;
+
+       /* we need to get the smbus version to activate the touchpad */
+       retval = rmi_smb_get_version(rmi_smb);
+       if (retval < 0)
+               return retval;
+
+       return 0;
+}
+
+static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
+{
+       struct rmi_smb_xport *rmi_smb =
+               container_of(xport, struct rmi_smb_xport, xport);
+
+       rmi_smb_clear_state(rmi_smb);
+
+       /*
+        * we do not call the actual reset command, it has to be handled in
+        * PS/2 or there will be races between PS/2 and SMBus.
+        * PS/2 should ensure that a psmouse_reset is called before
+        * intializing the device and after it has been removed to be in a known
+        * state.
+        */
+       return rmi_smb_enable_smbus_mode(rmi_smb);
+}
+
+static const struct rmi_transport_ops rmi_smb_ops = {
+       .write_block    = rmi_smb_write_block,
+       .read_block     = rmi_smb_read_block,
+       .reset          = rmi_smb_reset,
+};
+
+static int rmi_smb_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
+       struct rmi_smb_xport *rmi_smb;
+       int retval;
+       int smbus_version;
+
+       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");
+               return -ENODEV;
+       }
+
+       if (client->irq <= 0) {
+               dev_err(&client->dev, "no IRQ provided, giving up.\n");
+               return client->irq ? client->irq : -ENODEV;
+       }
+
+       rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
+                               GFP_KERNEL);
+       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",
+               dev_name(&client->dev));
+
+       rmi_smb->client = client;
+       mutex_init(&rmi_smb->page_mutex);
+       mutex_init(&rmi_smb->mappingtable_mutex);
+
+       rmi_smb->xport.dev = &client->dev;
+       rmi_smb->xport.pdata = *pdata;
+       rmi_smb->xport.pdata.irq = client->irq;
+       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 = 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",
+                               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, "registered rmi smb driver at %#04x.\n",
+                       client->addr);
+       return 0;
+
+}
+
+static int rmi_smb_remove(struct i2c_client *client)
+{
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+
+       rmi_unregister_transport_device(&rmi_smb->xport);
+
+       return 0;
+}
+
+static int __maybe_unused rmi_smb_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
+       if (ret)
+               dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+       return ret;
+}
+
+static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
+       if (ret)
+               dev_warn(dev, "Failed to suspend device: %d\n", ret);
+
+       return ret;
+}
+
+static int __maybe_unused rmi_smb_resume(struct device *dev)
+{
+       struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
+       int ret;
+
+       rmi_smb_reset(&rmi_smb->xport, 0);
+
+       rmi_reset(rmi_dev);
+
+       ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
+       if (ret)
+               dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+       return 0;
+}
+
+static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
+       int ret;
+
+       ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
+       if (ret)
+               dev_warn(dev, "Failed to resume device: %d\n", ret);
+
+       return 0;
+}
+
+static const struct dev_pm_ops rmi_smb_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
+       SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
+                          NULL)
+};
+
+static const struct i2c_device_id rmi_id[] = {
+       { "rmi4_smbus", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rmi_id);
+
+static struct i2c_driver rmi_smb_driver = {
+       .driver = {
+               .name   = "rmi4_smbus",
+               .pm     = &rmi_smb_pm,
+       },
+       .id_table       = rmi_id,
+       .probe          = rmi_smb_probe,
+       .remove         = rmi_smb_remove,
+};
+
+module_i2c_driver(rmi_smb_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
+MODULE_DESCRIPTION("RMI4 SMBus driver");
+MODULE_LICENSE("GPL");
index 4ebef607e2141ad574fe161366308c08e101dc68..69548d7d1f10f8f3d9fac4cc3e2e828971a7687c 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/rmi.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
-#include <linux/irq.h>
 #include <linux/of.h>
 #include "rmi_driver.h"
 
@@ -44,8 +43,6 @@ struct rmi_spi_xport {
        struct mutex page_mutex;
        int page;
 
-       int irq;
-
        u8 *rx_buf;
        u8 *tx_buf;
        int xfer_buf_size;
@@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = {
        .read_block     = rmi_spi_read_block,
 };
 
-static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
-{
-       struct rmi_spi_xport *rmi_spi = dev_id;
-       struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
-       int ret;
-
-       ret = rmi_process_interrupt_requests(rmi_dev);
-       if (ret)
-               rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
-                       "Failed to process interrupt request: %d\n", ret);
-
-       return IRQ_HANDLED;
-}
-
-static int rmi_spi_init_irq(struct spi_device *spi)
-{
-       struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
-       int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
-       int ret;
-
-       if (!irq_flags)
-               irq_flags = IRQF_TRIGGER_LOW;
-
-       ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
-                       rmi_spi_irq, irq_flags | IRQF_ONESHOT,
-                       dev_name(&spi->dev), rmi_spi);
-       if (ret < 0) {
-               dev_warn(&spi->dev, "Failed to register interrupt %d\n",
-                       rmi_spi->irq);
-               return ret;
-       }
-
-       return 0;
-}
-
 #ifdef CONFIG_OF
 static int rmi_spi_of_probe(struct spi_device *spi,
                        struct rmi_device_platform_data *pdata)
@@ -440,8 +402,7 @@ static int rmi_spi_probe(struct spi_device *spi)
                return retval;
        }
 
-       if (spi->irq > 0)
-               rmi_spi->irq = spi->irq;
+       pdata->irq = spi->irq;
 
        rmi_spi->spi = spi;
        mutex_init(&rmi_spi->page_mutex);
@@ -477,10 +438,6 @@ static int rmi_spi_probe(struct spi_device *spi)
        if (retval)
                return retval;
 
-       retval = rmi_spi_init_irq(spi);
-       if (retval < 0)
-               return retval;
-
        dev_info(&spi->dev, "registered RMI SPI driver\n");
        return 0;
 }
@@ -492,17 +449,10 @@ static int rmi_spi_suspend(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_spi->irq);
-       if (device_may_wakeup(&spi->dev)) {
-               ret = enable_irq_wake(rmi_spi->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to enable irq for wake: %d\n",
-                               ret);
-       }
        return ret;
 }
 
@@ -512,15 +462,7 @@ static int rmi_spi_resume(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       enable_irq(rmi_spi->irq);
-       if (device_may_wakeup(&spi->dev)) {
-               ret = disable_irq_wake(rmi_spi->irq);
-               if (!ret)
-                       dev_warn(dev, "Failed to disable irq for wake: %d\n",
-                               ret);
-       }
-
-       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
@@ -535,12 +477,10 @@ static int rmi_spi_runtime_suspend(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
-       disable_irq(rmi_spi->irq);
-
        return 0;
 }
 
@@ -550,9 +490,7 @@ static int rmi_spi_runtime_resume(struct device *dev)
        struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
        int ret;
 
-       enable_irq(rmi_spi->irq);
-
-       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
+       ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false);
        if (ret)
                dev_warn(dev, "Failed to resume device: %d\n", ret);
 
index 073246c7d1634eef411c1bf07d7f72ab47cad369..73a4e68448fc57fef4a09f0ccaacf19c41790acf 100644 (file)
@@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
+                       DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
                },
        },
        { }
@@ -1131,10 +1059,10 @@ static int __init i8042_pnp_init(void)
        return 0;
 }
 
-#else
+#else  /* !CONFIG_PNP */
 static inline int i8042_pnp_init(void) { return 0; }
 static inline void i8042_pnp_exit(void) { }
-#endif
+#endif /* CONFIG_PNP */
 
 static int __init i8042_platform_init(void)
 {
index 89abfdb539ac750ff50eca67f77b2fe6898ff6f0..62685a76891363b93d1d6a1d4db613fad814686b 100644 (file)
@@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
 
 
 /*
- * i8042_aux_close attempts to clear AUX or KBD port state by disabling
+ * i8042_port_close attempts to clear AUX or KBD port state by disabling
  * and then re-enabling it.
  */
 
index fe9877a6af9e252b37e8b9955bd31b06b8c801b7..d50ee490c9ccacf653a3b04dbecbc43b0f78ec2e 100644 (file)
@@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = {
        { .compatible = "fsl,imx25-tcq", },
        { /* Sentinel */ }
 };
+MODULE_DEVICE_TABLE(of, mx25_tcq_ids);
 
 #define TSC_4WIRE_PRE_INDEX 0
 #define TSC_4WIRE_X_INDEX 1
index 8275267eac25441f308e6103e82d48830d1feb71..7098e0a47019539b7cc3482fe3043576a123e348 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <linux/log2.h>
 
 /* ADC configuration registers field define */
 #define ADC_AIEN               (0x1 << 7)
 #define ADC_CONV_DISABLE       0x1F
+#define ADC_AVGE               (0x1 << 5)
 #define ADC_CAL                        (0x1 << 7)
 #define ADC_CALF               0x2
 #define ADC_12BIT_MODE         (0x2 << 2)
+#define ADC_CONV_MODE_MASK     (0x3 << 2)
 #define ADC_IPG_CLK            0x00
+#define ADC_INPUT_CLK_MASK     0x3
 #define ADC_CLK_DIV_8          (0x03 << 5)
+#define ADC_CLK_DIV_MASK       (0x3 << 5)
 #define ADC_SHORT_SAMPLE_MODE  (0x0 << 4)
+#define ADC_SAMPLE_MODE_MASK   (0x1 << 4)
 #define ADC_HARDWARE_TRIGGER   (0x1 << 13)
+#define ADC_AVGS_SHIFT         14
+#define ADC_AVGS_MASK          (0x3 << 14)
 #define SELECT_CHANNEL_4       0x04
 #define SELECT_CHANNEL_1       0x01
 #define DISABLE_CONVERSION_INT (0x0 << 7)
@@ -84,8 +92,10 @@ struct imx6ul_tsc {
        struct clk *adc_clk;
        struct gpio_desc *xnur_gpio;
 
-       int measure_delay_time;
-       int pre_charge_time;
+       u32 measure_delay_time;
+       u32 pre_charge_time;
+       bool average_enable;
+       u32 average_select;
 
        struct completion completion;
 };
@@ -96,17 +106,23 @@ struct imx6ul_tsc {
  */
 static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
 {
-       int adc_hc = 0;
-       int adc_gc;
-       int adc_gs;
-       int adc_cfg;
-       int timeout;
+       u32 adc_hc = 0;
+       u32 adc_gc;
+       u32 adc_gs;
+       u32 adc_cfg;
+       unsigned long timeout;
 
        reinit_completion(&tsc->completion);
 
        adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
+       adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
        adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
+       adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
        adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+       if (tsc->average_enable) {
+               adc_cfg &= ~ADC_AVGS_MASK;
+               adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+       }
        adc_cfg &= ~ADC_HARDWARE_TRIGGER;
        writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
 
@@ -118,6 +134,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
        /* start ADC calibration */
        adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
        adc_gc |= ADC_CAL;
+       if (tsc->average_enable)
+               adc_gc |= ADC_AVGE;
        writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
 
        timeout = wait_for_completion_timeout
@@ -148,7 +166,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
  */
 static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
 {
-       int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
+       u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
 
        adc_hc0 = DISABLE_CONVERSION_INT;
        writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
@@ -173,8 +191,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
  */
 static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
 {
-       int basic_setting = 0;
-       int start;
+       u32 basic_setting = 0;
+       u32 start;
 
        basic_setting |= tsc->measure_delay_time << 8;
        basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
@@ -209,8 +227,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
 
 static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
 {
-       int tsc_flow;
-       int adc_cfg;
+       u32 tsc_flow;
+       u32 adc_cfg;
 
        /* TSC controller enters to idle status */
        tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
@@ -227,8 +245,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
 static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(2);
-       int state_machine;
-       int debug_mode2;
+       u32 state_machine;
+       u32 debug_mode2;
 
        do {
                if (time_after(jiffies, timeout))
@@ -246,10 +264,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
 static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
 {
        struct imx6ul_tsc *tsc = dev_id;
-       int status;
-       int value;
-       int x, y;
-       int start;
+       u32 status;
+       u32 value;
+       u32 x, y;
+       u32 start;
 
        status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
 
@@ -289,8 +307,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
 static irqreturn_t adc_irq_fn(int irq, void *dev_id)
 {
        struct imx6ul_tsc *tsc = dev_id;
-       int coco;
-       int value;
+       u32 coco;
+       u32 value;
 
        coco = readl(tsc->adc_regs + REG_ADC_HS);
        if (coco & 0x01) {
@@ -346,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
        int err;
        int tsc_irq;
        int adc_irq;
+       u32 average_samples;
 
        tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
        if (!tsc)
@@ -450,6 +469,30 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
        if (err)
                tsc->pre_charge_time = 0xfff;
 
+       err = of_property_read_u32(np, "touchscreen-average-samples",
+                                  &average_samples);
+       if (err)
+               average_samples = 1;
+
+       switch (average_samples) {
+       case 1:
+               tsc->average_enable = false;
+               tsc->average_select = 0; /* value unused; initialize anyway */
+               break;
+       case 4:
+       case 8:
+       case 16:
+       case 32:
+               tsc->average_enable = true;
+               tsc->average_select = ilog2(average_samples) - 2;
+               break;
+       default:
+               dev_err(&pdev->dev,
+                       "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n",
+                       average_samples);
+               return -EINVAL;
+       }
+
        err = input_register_device(tsc->input);
        if (err) {
                dev_err(&pdev->dev,
index 552a3773f79d0b7815d6d180f7aabc9083ff6c92..703d7f983d0aff95bf451f9efba1564c05e5647f 100644 (file)
@@ -33,7 +33,7 @@
 
 /*****************************************************************
  * Protocol
- * Version : MIP 4.0 Rev 4.6
+ * Version : MIP 4.0 Rev 5.4
  *****************************************************************/
 
 /* Address */
@@ -81,6 +81,9 @@
 #define MIP4_R1_INFO_IC_HW_CATEGORY            0x77
 #define MIP4_R1_INFO_CONTACT_THD_SCR           0x78
 #define MIP4_R1_INFO_CONTACT_THD_KEY           0x7A
+#define MIP4_R1_INFO_PID                               0x7C
+#define MIP4_R1_INFO_VID                               0x7E
+#define MIP4_R1_INFO_SLAVE_ADDR                        0x80
 
 #define MIP4_R0_EVENT                          0x02
 #define MIP4_R1_EVENT_SUPPORTED_FUNC           0x00
@@ -157,7 +160,9 @@ struct mip4_ts {
 
        char phys[32];
        char product_name[16];
+       u16 product_id;
        char ic_name[4];
+       char fw_name[32];
 
        unsigned int max_x;
        unsigned int max_y;
@@ -264,6 +269,23 @@ static int mip4_query_device(struct mip4_ts *ts)
                dev_dbg(&ts->client->dev, "product name: %.*s\n",
                        (int)sizeof(ts->product_name), ts->product_name);
 
+       /* Product ID */
+       cmd[0] = MIP4_R0_INFO;
+       cmd[1] = MIP4_R1_INFO_PID;
+       error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2);
+       if (error) {
+               dev_warn(&ts->client->dev,
+                        "Failed to retrieve product id: %d\n", error);
+       } else {
+               ts->product_id = get_unaligned_le16(&buf[0]);
+               dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id);
+       }
+
+       /* Firmware name */
+       snprintf(ts->fw_name, sizeof(ts->fw_name),
+               "melfas_mip4_%04X.fw", ts->product_id);
+       dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name);
+
        /* IC name */
        cmd[0] = MIP4_R0_INFO;
        cmd[1] = MIP4_R1_INFO_IC_NAME;
@@ -1269,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
        const struct firmware *fw;
        int error;
 
-       error = request_firmware(&fw, MIP4_FW_NAME, dev);
+       error = request_firmware(&fw, ts->fw_name, dev);
        if (error) {
                dev_err(&ts->client->dev,
                        "Failed to retrieve firmware %s: %d\n",
-                       MIP4_FW_NAME, error);
+                       ts->fw_name, error);
                return error;
        }
 
@@ -1348,6 +1370,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
 
 static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
 
+static ssize_t mip4_sysfs_read_product_id(struct device *dev,
+                                         struct device_attribute *attr,
+                                         char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct mip4_ts *ts = i2c_get_clientdata(client);
+       size_t count;
+
+       mutex_lock(&ts->input->mutex);
+
+       count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id);
+
+       mutex_unlock(&ts->input->mutex);
+
+       return count;
+}
+
+static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL);
+
 static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
                                          struct device_attribute *attr,
                                          char *buf)
@@ -1371,6 +1412,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
 static struct attribute *mip4_attrs[] = {
        &dev_attr_fw_version.attr,
        &dev_attr_hw_version.attr,
+       &dev_attr_product_id.attr,
        &dev_attr_ic_name.attr,
        &dev_attr_update_fw.attr,
        NULL,
@@ -1435,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
        input->id.bustype = BUS_I2C;
        input->id.vendor = 0x13c5;
+       input->id.product = ts->product_id;
 
        input->open = mip4_input_open;
        input->close = mip4_input_close;
@@ -1572,6 +1615,6 @@ static struct i2c_driver mip4_driver = {
 module_i2c_driver(mip4_driver);
 
 MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
-MODULE_VERSION("2016.09.28");
+MODULE_VERSION("2016.10.31");
 MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
 MODULE_LICENSE("GPL");
index a99fb5cac5a0e189c20360aaba33c6c2ab1ad25f..2658afa016c94a88bc04489772a183e6e687c2e5 100644 (file)
@@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
 
                if (ts->boot_mode == RAYDIUM_TS_MAIN) {
                        dev_err(&client->dev,
-                               "failied to jump to boot loader: %d\n",
+                               "failed to jump to boot loader: %d\n",
                                error);
                        return -EIO;
                }
index f502c8488be86361592187acdffdecb164c4dfbd..404830a4a36630822aaa29aa7bcec77fdcd6bc3b 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/input/touchscreen.h>
 #include <linux/pm.h>
 #include <linux/irq.h>
+#include <linux/regulator/consumer.h>
 
 #include <asm/unaligned.h>
 
@@ -73,6 +74,7 @@ struct silead_ts_data {
        struct i2c_client *client;
        struct gpio_desc *gpio_power;
        struct input_dev *input;
+       struct regulator_bulk_data regulators[2];
        char fw_name[64];
        struct touchscreen_properties prop;
        u32 max_fingers;
@@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data,
 }
 #endif
 
+static void silead_disable_regulator(void *arg)
+{
+       struct silead_ts_data *data = arg;
+
+       regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
+}
+
 static int silead_ts_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
@@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client,
        if (client->irq <= 0)
                return -ENODEV;
 
+       data->regulators[0].supply = "vddio";
+       data->regulators[1].supply = "avdd";
+       error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators),
+                                       data->regulators);
+       if (error)
+               return error;
+
+       /*
+        * Enable regulators at probe and disable them at remove, we need
+        * to keep the chip powered otherwise it forgets its firmware.
+        */
+       error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
+                                     data->regulators);
+       if (error)
+               return error;
+
+       error = devm_add_action_or_reset(dev, silead_disable_regulator, data);
+       if (error)
+               return error;
+
        /* Power GPIO pin */
        data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
        if (IS_ERR(data->gpio_power)) {
index ee2d8c6f91300db725b3681c830d4568de71cb19..0b71024c082c37f817b4b0303a826abaa796fc95 100644 (file)
@@ -2,7 +2,6 @@
 #define _GPIO_KEYS_H
 
 struct device;
-struct gpio_desc;
 
 /**
  * struct gpio_keys_button - configuration parameters
@@ -18,7 +17,6 @@ struct gpio_desc;
  *                     disable button via sysfs
  * @value:             axis value for %EV_ABS
  * @irq:               Irq number in case of interrupt keys
- * @gpiod:             GPIO descriptor
  */
 struct gpio_keys_button {
        unsigned int code;
@@ -31,7 +29,6 @@ struct gpio_keys_button {
        bool can_disable;
        int value;
        unsigned int irq;
-       struct gpio_desc *gpiod;
 };
 
 /**
@@ -46,7 +43,7 @@ struct gpio_keys_button {
  * @name:              input device name
  */
 struct gpio_keys_platform_data {
-       struct gpio_keys_button *buttons;
+       const struct gpio_keys_button *buttons;
        int nbuttons;
        unsigned int poll_interval;
        unsigned int rep:1;
diff --git a/include/linux/platform_data/drv260x-pdata.h b/include/linux/platform_data/drv260x-pdata.h
deleted file mode 100644 (file)
index 0a03b09..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Platform data for DRV260X haptics driver family
- *
- * Author: Dan Murphy <dmurphy@ti.com>
- *
- * Copyright:   (C) 2014 Texas Instruments, 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- */
-
-#ifndef _LINUX_DRV260X_PDATA_H
-#define _LINUX_DRV260X_PDATA_H
-
-struct drv260x_platform_data {
-       u32 library_selection;
-       u32 mode;
-       u32 vib_rated_voltage;
-       u32 vib_overdrive_voltage;
-};
-
-#endif
index e0aca147600169a6fa67dcb3c7d5f7725a52a9d6..64125443f8a638e787adfbaebab4755f5d63852a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
+#include <linux/kfifo.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -99,6 +100,8 @@ struct rmi_2d_sensor_platform_data {
        bool topbuttonpad;
        bool kernel_tracking;
        int dmax;
+       int dribble;
+       int palm_detect;
 };
 
 /**
@@ -106,7 +109,7 @@ struct rmi_2d_sensor_platform_data {
  * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
  * button that is found.
  * @trackstick_buttons - Set when the function 30 is handling the physical
- * buttons of the trackstick (as a PD/2 passthrough device.
+ * buttons of the trackstick (as a PS/2 passthrough device).
  * @disable - the touchpad incorrectly reports F30 and it should be ignored.
  * This is a special case which is due to misconfigured firmware.
  */
@@ -116,14 +119,17 @@ struct rmi_f30_data {
        bool disable;
 };
 
-/**
- * struct rmi_f01_power - override default power management settings.
- *
+
+/*
+ * Set the state of a register
+ *     DEFAULT - use the default value set by the firmware config
+ *     OFF - explicitly disable the register
+ *     ON - explicitly enable the register
  */
-enum rmi_f01_nosleep {
-       RMI_F01_NOSLEEP_DEFAULT = 0,
-       RMI_F01_NOSLEEP_OFF = 1,
-       RMI_F01_NOSLEEP_ON = 2
+enum rmi_reg_state {
+       RMI_REG_STATE_DEFAULT = 0,
+       RMI_REG_STATE_OFF = 1,
+       RMI_REG_STATE_ON = 2
 };
 
 /**
@@ -143,7 +149,7 @@ enum rmi_f01_nosleep {
  * when the touch sensor is in doze mode, in units of 10ms.
  */
 struct rmi_f01_power_management {
-       enum rmi_f01_nosleep nosleep;
+       enum rmi_reg_state nosleep;
        u8 wakeup_threshold;
        u8 doze_holdoff;
        u8 doze_interval;
@@ -204,16 +210,18 @@ struct rmi_device_platform_data_spi {
  * @reset_delay_ms - after issuing a reset command to the touch sensor, the
  * driver waits a few milliseconds to give the firmware a chance to
  * to re-initialize.  You can override the default wait period here.
+ * @irq: irq associated with the attn gpio line, or negative
  */
 struct rmi_device_platform_data {
        int reset_delay_ms;
+       int irq;
 
        struct rmi_device_platform_data_spi spi_data;
 
        /* function handler pdata */
-       struct rmi_2d_sensor_platform_data *sensor_pdata;
+       struct rmi_2d_sensor_platform_data sensor_pdata;
        struct rmi_f01_power_management power_management;
-       struct rmi_f30_data *f30_data;
+       struct rmi_f30_data f30_data;
 };
 
 /**
@@ -264,9 +272,6 @@ struct rmi_transport_dev {
        struct rmi_device_platform_data pdata;
 
        struct input_dev *input;
-
-       void *attn_data;
-       int attn_size;
 };
 
 /**
@@ -324,17 +329,24 @@ struct rmi_device {
 
 };
 
+struct rmi4_attn_data {
+       unsigned long irq_status;
+       size_t size;
+       void *data;
+};
+
 struct rmi_driver_data {
        struct list_head function_list;
 
        struct rmi_device *rmi_dev;
 
        struct rmi_function *f01_container;
-       bool f01_bootloader_mode;
+       struct rmi_function *f34_container;
+       bool bootloader_mode;
 
-       u32 attn_count;
        int num_of_irq_regs;
        int irq_count;
+       void *irq_memory;
        unsigned long *irq_status;
        unsigned long *fn_irq_bits;
        unsigned long *current_irq_mask;
@@ -343,17 +355,23 @@ struct rmi_driver_data {
        struct input_dev *input;
 
        u8 pdt_props;
-       u8 bsr;
+
+       u8 num_rx_electrodes;
+       u8 num_tx_electrodes;
 
        bool enabled;
+       struct mutex enabled_mutex;
 
-       void *data;
+       struct rmi4_attn_data attn_data;
+       DECLARE_KFIFO(attn_fifo, struct rmi4_attn_data, 16);
 };
 
 int rmi_register_transport_device(struct rmi_transport_dev *xport);
 void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
 
-int rmi_driver_suspend(struct rmi_device *rmi_dev);
-int rmi_driver_resume(struct rmi_device *rmi_dev);
+void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
+                      void *data, size_t size);
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake);
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake);
 #endif