Merge tag 'v3.15-rc5' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 14 May 2014 23:49:19 +0000 (16:49 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 14 May 2014 23:49:19 +0000 (16:49 -0700)
Merge with Linux 3.15-rc5 to sync up Wacom and other changes.

35 files changed:
Documentation/devicetree/bindings/input/st-keyscan.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/sun4i.txt [new file with mode: 0644]
drivers/input/evdev.c
drivers/input/input-polldev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/Makefile
drivers/input/keyboard/clps711x-keypad.c
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/gpio_keys_polled.c
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/st-keyscan.c [new file with mode: 0644]
drivers/input/keyboard/tc3589x-keypad.c
drivers/input/misc/Kconfig
drivers/input/misc/gpio-beeper.c
drivers/input/misc/pmic8xxx-pwrkey.c
drivers/input/misc/rotary_encoder.c
drivers/input/misc/twl6040-vibra.c
drivers/input/mouse/Kconfig
drivers/input/serio/apbps2.c
drivers/input/serio/olpc_apsp.c
drivers/input/tablet/wacom_wac.c
drivers/input/tablet/wacom_wac.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/ad7877.c
drivers/input/touchscreen/ads7846.c
drivers/input/touchscreen/auo-pixcir-ts.c
drivers/input/touchscreen/egalax_ts.c
drivers/input/touchscreen/lpc32xx_ts.c
drivers/input/touchscreen/mms114.c
drivers/input/touchscreen/sun4i-ts.c [new file with mode: 0644]
drivers/input/touchscreen/tsc2005.c
drivers/input/touchscreen/zforce_ts.c
include/linux/gpio_keys.h
include/linux/input-polldev.h

diff --git a/Documentation/devicetree/bindings/input/st-keyscan.txt b/Documentation/devicetree/bindings/input/st-keyscan.txt
new file mode 100644 (file)
index 0000000..51eb428
--- /dev/null
@@ -0,0 +1,60 @@
+* ST Keyscan controller Device Tree bindings
+
+The ST keyscan controller Device Tree binding is based on the
+matrix-keymap.
+
+Required properties:
+- compatible: "st,sti-keyscan"
+
+- reg: Register base address and size of st-keyscan controller.
+
+- interrupts: Interrupt number for the st-keyscan controller.
+
+- clocks: Must contain one entry, for the module clock.
+  See ../clocks/clock-bindings.txt for details.
+
+- pinctrl: Should specify pin control groups used for this controller.
+  See ../pinctrl/pinctrl-bindings.txt for details.
+
+- linux,keymap: The keymap for keys as described in the binding document
+  devicetree/bindings/input/matrix-keymap.txt.
+
+- keypad,num-rows: Number of row lines connected to the keypad controller.
+
+- keypad,num-columns: Number of column lines connected to the keypad
+  controller.
+
+Optional property:
+- st,debounce_us: Debouncing interval time in microseconds
+
+Example:
+
+keyscan: keyscan@fe4b0000 {
+       compatible = "st,sti-keyscan";
+       reg = <0xfe4b0000 0x2000>;
+       interrupts = <GIC_SPI 212 IRQ_TYPE_NONE>;
+       clocks  = <&CLK_SYSIN>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_keyscan>;
+
+       keypad,num-rows = <4>;
+       keypad,num-columns = <4>;
+       st,debounce_us = <5000>;
+
+       linux,keymap = < MATRIX_KEY(0x00, 0x00, KEY_F13)
+                        MATRIX_KEY(0x00, 0x01, KEY_F9)
+                        MATRIX_KEY(0x00, 0x02, KEY_F5)
+                        MATRIX_KEY(0x00, 0x03, KEY_F1)
+                        MATRIX_KEY(0x01, 0x00, KEY_F14)
+                        MATRIX_KEY(0x01, 0x01, KEY_F10)
+                        MATRIX_KEY(0x01, 0x02, KEY_F6)
+                        MATRIX_KEY(0x01, 0x03, KEY_F2)
+                        MATRIX_KEY(0x02, 0x00, KEY_F15)
+                        MATRIX_KEY(0x02, 0x01, KEY_F11)
+                        MATRIX_KEY(0x02, 0x02, KEY_F7)
+                        MATRIX_KEY(0x02, 0x03, KEY_F3)
+                        MATRIX_KEY(0x03, 0x00, KEY_F16)
+                        MATRIX_KEY(0x03, 0x01, KEY_F12)
+                        MATRIX_KEY(0x03, 0x02, KEY_F8)
+                        MATRIX_KEY(0x03, 0x03, KEY_F4) >;
+       };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
new file mode 100644 (file)
index 0000000..aef5779
--- /dev/null
@@ -0,0 +1,20 @@
+sun4i resistive touchscreen controller
+--------------------------------------
+
+Required properties:
+ - compatible: "allwinner,sun4i-a10-ts"
+ - reg: mmio address range of the chip
+ - interrupts: interrupt to which the chip is connected
+
+Optional properties:
+ - allwinner,ts-attached: boolean indicating that an actual touchscreen is
+                         attached to the controller
+
+Example:
+
+       rtp: rtp@01c25000 {
+               compatible = "allwinner,sun4i-a10-ts";
+               reg = <0x01c25000 0x100>;
+               interrupts = <29>;
+               allwinner,ts-attached;
+       };
index ce953d8..fd325ec 100644 (file)
@@ -629,12 +629,10 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
        return copy_to_user(p, str, len) ? -EFAULT : len;
 }
 
-#define OLD_KEY_MAX    0x1ff
 static int handle_eviocgbit(struct input_dev *dev,
                            unsigned int type, unsigned int size,
                            void __user *p, int compat_mode)
 {
-       static unsigned long keymax_warn_time;
        unsigned long *bits;
        int len;
 
@@ -652,24 +650,8 @@ static int handle_eviocgbit(struct input_dev *dev,
        default: return -EINVAL;
        }
 
-       /*
-        * Work around bugs in userspace programs that like to do
-        * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
-        * should be in bytes, not in bits.
-        */
-       if (type == EV_KEY && size == OLD_KEY_MAX) {
-               len = OLD_KEY_MAX;
-               if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
-                       pr_warning("(EVIOCGBIT): Suspicious buffer size %u, "
-                                  "limiting output to %zu bytes. See "
-                                  "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
-                                  OLD_KEY_MAX,
-                                  BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
-       }
-
        return bits_to_user(bits, len, size, p, compat_mode);
 }
-#undef OLD_KEY_MAX
 
 static int evdev_handle_get_keycode(struct input_dev *dev, void __user *p)
 {
index 7f161d9..3664f81 100644 (file)
@@ -147,6 +147,11 @@ static struct attribute_group input_polldev_attribute_group = {
        .attrs = sysfs_attrs
 };
 
+static const struct attribute_group *input_polldev_attribute_groups[] = {
+       &input_polldev_attribute_group,
+       NULL
+};
+
 /**
  * input_allocate_polled_device - allocate memory for polled device
  *
@@ -171,6 +176,91 @@ struct input_polled_dev *input_allocate_polled_device(void)
 }
 EXPORT_SYMBOL(input_allocate_polled_device);
 
+struct input_polled_devres {
+       struct input_polled_dev *polldev;
+};
+
+static int devm_input_polldev_match(struct device *dev, void *res, void *data)
+{
+       struct input_polled_devres *devres = res;
+
+       return devres->polldev == data;
+}
+
+static void devm_input_polldev_release(struct device *dev, void *res)
+{
+       struct input_polled_devres *devres = res;
+       struct input_polled_dev *polldev = devres->polldev;
+
+       dev_dbg(dev, "%s: dropping reference/freeing %s\n",
+               __func__, dev_name(&polldev->input->dev));
+
+       input_put_device(polldev->input);
+       kfree(polldev);
+}
+
+static void devm_input_polldev_unregister(struct device *dev, void *res)
+{
+       struct input_polled_devres *devres = res;
+       struct input_polled_dev *polldev = devres->polldev;
+
+       dev_dbg(dev, "%s: unregistering device %s\n",
+               __func__, dev_name(&polldev->input->dev));
+       input_unregister_device(polldev->input);
+
+       /*
+        * Note that we are still holding extra reference to the input
+        * device so it will stick around until devm_input_polldev_release()
+        * is called.
+        */
+}
+
+/**
+ * devm_input_allocate_polled_device - allocate managed polled device
+ * @dev: device owning the polled device being created
+ *
+ * Returns prepared &struct input_polled_dev or %NULL.
+ *
+ * Managed polled input devices do not need to be explicitly unregistered
+ * or freed as it will be done automatically when owner device unbinds
+ * from * its driver (or binding fails). Once such managed polled device
+ * is allocated, it is ready to be set up and registered in the same
+ * fashion as regular polled input devices (using
+ * input_register_polled_device() function).
+ *
+ * If you want to manually unregister and free such managed polled devices,
+ * it can be still done by calling input_unregister_polled_device() and
+ * input_free_polled_device(), although it is rarely needed.
+ *
+ * NOTE: the owner device is set up as parent of input device and users
+ * should not override it.
+ */
+struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev)
+{
+       struct input_polled_dev *polldev;
+       struct input_polled_devres *devres;
+
+       devres = devres_alloc(devm_input_polldev_release, sizeof(*devres),
+                             GFP_KERNEL);
+       if (!devres)
+               return NULL;
+
+       polldev = input_allocate_polled_device();
+       if (!polldev) {
+               devres_free(devres);
+               return NULL;
+       }
+
+       polldev->input->dev.parent = dev;
+       polldev->devres_managed = true;
+
+       devres->polldev = polldev;
+       devres_add(dev, devres);
+
+       return polldev;
+}
+EXPORT_SYMBOL(devm_input_allocate_polled_device);
+
 /**
  * input_free_polled_device - free memory allocated for polled device
  * @dev: device to free
@@ -181,7 +271,12 @@ EXPORT_SYMBOL(input_allocate_polled_device);
 void input_free_polled_device(struct input_polled_dev *dev)
 {
        if (dev) {
-               input_free_device(dev->input);
+               if (dev->devres_managed)
+                       WARN_ON(devres_destroy(dev->input->dev.parent,
+                                               devm_input_polldev_release,
+                                               devm_input_polldev_match,
+                                               dev));
+               input_put_device(dev->input);
                kfree(dev);
        }
 }
@@ -199,26 +294,35 @@ EXPORT_SYMBOL(input_free_polled_device);
  */
 int input_register_polled_device(struct input_polled_dev *dev)
 {
+       struct input_polled_devres *devres = NULL;
        struct input_dev *input = dev->input;
        int error;
 
+       if (dev->devres_managed) {
+               devres = devres_alloc(devm_input_polldev_unregister,
+                                     sizeof(*devres), GFP_KERNEL);
+               if (!devres)
+                       return -ENOMEM;
+
+               devres->polldev = dev;
+       }
+
        input_set_drvdata(input, dev);
        INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
+
        if (!dev->poll_interval)
                dev->poll_interval = 500;
        if (!dev->poll_interval_max)
                dev->poll_interval_max = dev->poll_interval;
+
        input->open = input_open_polled_device;
        input->close = input_close_polled_device;
 
-       error = input_register_device(input);
-       if (error)
-               return error;
+       input->dev.groups = input_polldev_attribute_groups;
 
-       error = sysfs_create_group(&input->dev.kobj,
-                                  &input_polldev_attribute_group);
+       error = input_register_device(input);
        if (error) {
-               input_unregister_device(input);
+               devres_free(devres);
                return error;
        }
 
@@ -231,6 +335,12 @@ int input_register_polled_device(struct input_polled_dev *dev)
         */
        input_get_device(input);
 
+       if (dev->devres_managed) {
+               dev_dbg(input->dev.parent, "%s: registering %s with devres.\n",
+                       __func__, dev_name(&input->dev));
+               devres_add(input->dev.parent, devres);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(input_register_polled_device);
@@ -245,8 +355,11 @@ EXPORT_SYMBOL(input_register_polled_device);
  */
 void input_unregister_polled_device(struct input_polled_dev *dev)
 {
-       sysfs_remove_group(&dev->input->dev.kobj,
-                          &input_polldev_attribute_group);
+       if (dev->devres_managed)
+               WARN_ON(devres_destroy(dev->input->dev.parent,
+                                       devm_input_polldev_unregister,
+                                       devm_input_polldev_match,
+                                       dev));
 
        input_unregister_device(dev->input);
 }
index 76842d7..948a303 100644 (file)
@@ -524,6 +524,17 @@ config KEYBOARD_STOWAWAY
          To compile this driver as a module, choose M here: the
          module will be called stowaway.
 
+config KEYBOARD_ST_KEYSCAN
+       tristate "STMicroelectronics keyscan support"
+       depends on ARCH_STI || COMPILE_TEST
+       select INPUT_MATRIXKMAP
+       help
+         Say Y here if you want to use a keypad attached to the keyscan block
+         on some STMicroelectronics SoC devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called st-keyscan.
+
 config KEYBOARD_SUNKBD
        tristate "Sun Type 4 and Type 5 keyboard"
        select SERIO
index 11cff7b..7504ae1 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC)               += sh_keysc.o
 obj-$(CONFIG_KEYBOARD_SPEAR)           += spear-keyboard.o
 obj-$(CONFIG_KEYBOARD_STMPE)           += stmpe-keypad.o
 obj-$(CONFIG_KEYBOARD_STOWAWAY)                += stowaway.o
+obj-$(CONFIG_KEYBOARD_ST_KEYSCAN)      += st-keyscan.o
 obj-$(CONFIG_KEYBOARD_SUNKBD)          += sunkbd.o
 obj-$(CONFIG_KEYBOARD_TC3589X)         += tc3589x-keypad.o
 obj-$(CONFIG_KEYBOARD_TEGRA)           += tegra-kbc.o
index 3955aec..552b65c 100644 (file)
@@ -185,7 +185,7 @@ static int clps711x_keypad_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id clps711x_keypad_of_match[] = {
+static const struct of_device_id clps711x_keypad_of_match[] = {
        { .compatible = "cirrus,clps711x-keypad", },
        { }
 };
index 2db1324..8c98e97 100644 (file)
@@ -424,6 +424,16 @@ out:
        return IRQ_HANDLED;
 }
 
+static void gpio_keys_quiesce_key(void *data)
+{
+       struct gpio_button_data *bdata = data;
+
+       if (bdata->timer_debounce)
+               del_timer_sync(&bdata->timer);
+
+       cancel_work_sync(&bdata->work);
+}
+
 static int gpio_keys_setup_key(struct platform_device *pdev,
                                struct input_dev *input,
                                struct gpio_button_data *bdata,
@@ -433,7 +443,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        struct device *dev = &pdev->dev;
        irq_handler_t isr;
        unsigned long irqflags;
-       int irq, error;
+       int irq;
+       int error;
 
        bdata->input = input;
        bdata->button = button;
@@ -441,7 +452,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 
        if (gpio_is_valid(button->gpio)) {
 
-               error = gpio_request_one(button->gpio, GPIOF_IN, desc);
+               error = devm_gpio_request_one(&pdev->dev, button->gpio,
+                                             GPIOF_IN, desc);
                if (error < 0) {
                        dev_err(dev, "Failed to request GPIO %d, error %d\n",
                                button->gpio, error);
@@ -463,7 +475,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                        dev_err(dev,
                                "Unable to get irq number for GPIO %d, error %d\n",
                                button->gpio, error);
-                       goto fail;
+                       return error;
                }
                bdata->irq = irq;
 
@@ -496,6 +508,18 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 
        input_set_capability(input, button->type ?: EV_KEY, button->code);
 
+       /*
+        * Install custom action to cancel debounce timer and
+        * workqueue item.
+        */
+       error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
+       if (error) {
+               dev_err(&pdev->dev,
+                       "failed to register quiesce action, error: %d\n",
+                       error);
+               return error;
+       }
+
        /*
         * If platform has specified that the button can be disabled,
         * we don't want it to share the interrupt line.
@@ -503,20 +527,15 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        if (!button->can_disable)
                irqflags |= IRQF_SHARED;
 
-       error = request_any_context_irq(bdata->irq, isr, irqflags, desc, bdata);
+       error = devm_request_any_context_irq(&pdev->dev, bdata->irq,
+                                            isr, irqflags, desc, bdata);
        if (error < 0) {
                dev_err(dev, "Unable to claim irq %d; error %d\n",
                        bdata->irq, error);
-               goto fail;
+               return error;
        }
 
        return 0;
-
-fail:
-       if (gpio_is_valid(button->gpio))
-               gpio_free(button->gpio);
-
-       return error;
 }
 
 static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
@@ -578,23 +597,18 @@ gpio_keys_get_devtree_pdata(struct device *dev)
        int i;
 
        node = dev->of_node;
-       if (!node) {
-               error = -ENODEV;
-               goto err_out;
-       }
+       if (!node)
+               return ERR_PTR(-ENODEV);
 
        nbuttons = of_get_child_count(node);
-       if (nbuttons == 0) {
-               error = -ENODEV;
-               goto err_out;
-       }
+       if (nbuttons == 0)
+               return ERR_PTR(-ENODEV);
 
-       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
-                       GFP_KERNEL);
-       if (!pdata) {
-               error = -ENOMEM;
-               goto err_out;
-       }
+       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);
        pdata->nbuttons = nbuttons;
@@ -619,7 +633,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                                dev_err(dev,
                                        "Failed to get gpio flags, error: %d\n",
                                        error);
-                       goto err_free_pdata;
+                       return ERR_PTR(error);
                }
 
                button = &pdata->buttons[i++];
@@ -630,8 +644,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
                        dev_err(dev, "Button without keycode: 0x%x\n",
                                button->gpio);
-                       error = -EINVAL;
-                       goto err_free_pdata;
+                       return ERR_PTR(-EINVAL);
                }
 
                button->desc = of_get_property(pp, "label", NULL);
@@ -646,20 +659,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
                        button->debounce_interval = 5;
        }
 
-       if (pdata->nbuttons == 0) {
-               error = -EINVAL;
-               goto err_free_pdata;
-       }
+       if (pdata->nbuttons == 0)
+               return ERR_PTR(-EINVAL);
 
        return pdata;
-
-err_free_pdata:
-       kfree(pdata);
-err_out:
-       return ERR_PTR(error);
 }
 
-static struct of_device_id gpio_keys_of_match[] = {
+static const struct of_device_id gpio_keys_of_match[] = {
        { .compatible = "gpio-keys", },
        { },
 };
@@ -675,22 +681,13 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
 #endif
 
-static void gpio_remove_key(struct gpio_button_data *bdata)
-{
-       free_irq(bdata->irq, bdata);
-       if (bdata->timer_debounce)
-               del_timer_sync(&bdata->timer);
-       cancel_work_sync(&bdata->work);
-       if (gpio_is_valid(bdata->button->gpio))
-               gpio_free(bdata->button->gpio);
-}
-
 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 gpio_keys_drvdata *ddata;
        struct input_dev *input;
+       size_t size;
        int i, error;
        int wakeup = 0;
 
@@ -700,14 +697,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
                        return PTR_ERR(pdata);
        }
 
-       ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
-                       pdata->nbuttons * sizeof(struct gpio_button_data),
-                       GFP_KERNEL);
-       input = input_allocate_device();
-       if (!ddata || !input) {
+       size = sizeof(struct gpio_keys_drvdata) +
+                       pdata->nbuttons * sizeof(struct gpio_button_data);
+       ddata = devm_kzalloc(dev, size, GFP_KERNEL);
+       if (!ddata) {
                dev_err(dev, "failed to allocate state\n");
-               error = -ENOMEM;
-               goto fail1;
+               return -ENOMEM;
+       }
+
+       input = devm_input_allocate_device(dev);
+       if (!input) {
+               dev_err(dev, "failed to allocate input device\n");
+               return -ENOMEM;
        }
 
        ddata->pdata = pdata;
@@ -738,7 +739,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
 
                error = gpio_keys_setup_key(pdev, input, bdata, button);
                if (error)
-                       goto fail2;
+                       return error;
 
                if (button->wakeup)
                        wakeup = 1;
@@ -748,57 +749,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
        if (error) {
                dev_err(dev, "Unable to export keys/switches, error: %d\n",
                        error);
-               goto fail2;
+               return error;
        }
 
        error = input_register_device(input);
        if (error) {
                dev_err(dev, "Unable to register input device, error: %d\n",
                        error);
-               goto fail3;
+               goto err_remove_group;
        }
 
        device_init_wakeup(&pdev->dev, wakeup);
 
        return 0;
 
- fail3:
+err_remove_group:
        sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
- fail2:
-       while (--i >= 0)
-               gpio_remove_key(&ddata->data[i]);
-
- fail1:
-       input_free_device(input);
-       kfree(ddata);
-       /* If we have no platform data, we allocated pdata dynamically. */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(pdata);
-
        return error;
 }
 
 static int gpio_keys_remove(struct platform_device *pdev)
 {
-       struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
-       struct input_dev *input = ddata->input;
-       int i;
-
        sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
 
        device_init_wakeup(&pdev->dev, 0);
 
-       for (i = 0; i < ddata->pdata->nbuttons; i++)
-               gpio_remove_key(&ddata->data[i]);
-
-       input_unregister_device(input);
-
-       /* If we have no platform data, we allocated pdata dynamically. */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(ddata->pdata);
-
-       kfree(ddata);
-
        return 0;
 }
 
index e571e19..432d363 100644 (file)
@@ -120,12 +120,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
        if (nbuttons == 0)
                return NULL;
 
-       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
-                       GFP_KERNEL);
-       if (!pdata) {
-               error = -ENOMEM;
-               goto err_out;
-       }
+       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);
        pdata->nbuttons = nbuttons;
@@ -151,7 +149,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                                dev_err(dev,
                                        "Failed to get gpio flags, error: %d\n",
                                        error);
-                       goto err_free_pdata;
+                       return ERR_PTR(error);
                }
 
                button = &pdata->buttons[i++];
@@ -162,8 +160,7 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
                        dev_err(dev, "Button without keycode: 0x%x\n",
                                button->gpio);
-                       error = -EINVAL;
-                       goto err_free_pdata;
+                       return ERR_PTR(-EINVAL);
                }
 
                button->desc = of_get_property(pp, "label", NULL);
@@ -178,20 +175,13 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
                        button->debounce_interval = 5;
        }
 
-       if (pdata->nbuttons == 0) {
-               error = -EINVAL;
-               goto err_free_pdata;
-       }
+       if (pdata->nbuttons == 0)
+               return ERR_PTR(-EINVAL);
 
        return pdata;
-
-err_free_pdata:
-       kfree(pdata);
-err_out:
-       return ERR_PTR(error);
 }
 
-static struct of_device_id gpio_keys_polled_of_match[] = {
+static const struct of_device_id gpio_keys_polled_of_match[] = {
        { .compatible = "gpio-keys-polled", },
        { },
 };
@@ -213,6 +203,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
        struct gpio_keys_polled_dev *bdev;
        struct input_polled_dev *poll_dev;
        struct input_dev *input;
+       size_t size;
        int error;
        int i;
 
@@ -228,24 +219,21 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
        if (!pdata->poll_interval) {
                dev_err(dev, "missing poll_interval value\n");
-               error = -EINVAL;
-               goto err_free_pdata;
+               return -EINVAL;
        }
 
-       bdev = kzalloc(sizeof(struct gpio_keys_polled_dev) +
-                      pdata->nbuttons * sizeof(struct gpio_keys_button_data),
-                      GFP_KERNEL);
+       size = sizeof(struct gpio_keys_polled_dev) +
+                       pdata->nbuttons * sizeof(struct gpio_keys_button_data);
+       bdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
        if (!bdev) {
                dev_err(dev, "no memory for private data\n");
-               error = -ENOMEM;
-               goto err_free_pdata;
+               return -ENOMEM;
        }
 
-       poll_dev = input_allocate_polled_device();
+       poll_dev = devm_input_allocate_polled_device(&pdev->dev);
        if (!poll_dev) {
                dev_err(dev, "no memory for polled device\n");
-               error = -ENOMEM;
-               goto err_free_bdev;
+               return -ENOMEM;
        }
 
        poll_dev->private = bdev;
@@ -258,7 +246,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
        input->name = pdev->name;
        input->phys = DRV_NAME"/input0";
-       input->dev.parent = &pdev->dev;
 
        input->id.bustype = BUS_HOST;
        input->id.vendor = 0x0001;
@@ -277,16 +264,15 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
 
                if (button->wakeup) {
                        dev_err(dev, DRV_NAME " does not support wakeup\n");
-                       error = -EINVAL;
-                       goto err_free_gpio;
+                       return -EINVAL;
                }
 
-               error = gpio_request_one(gpio, GPIOF_IN,
-                                        button->desc ?: DRV_NAME);
+               error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
+                                             button->desc ? : DRV_NAME);
                if (error) {
                        dev_err(dev, "unable to claim gpio %u, err=%d\n",
                                gpio, error);
-                       goto err_free_gpio;
+                       return error;
                }
 
                bdata->can_sleep = gpio_cansleep(gpio);
@@ -306,7 +292,7 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
        if (error) {
                dev_err(dev, "unable to register polled device, err=%d\n",
                        error);
-               goto err_free_gpio;
+               return error;
        }
 
        /* report initial state of the buttons */
@@ -315,52 +301,10 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
                                             &bdev->data[i]);
 
        return 0;
-
-err_free_gpio:
-       while (--i >= 0)
-               gpio_free(pdata->buttons[i].gpio);
-
-       input_free_polled_device(poll_dev);
-
-err_free_bdev:
-       kfree(bdev);
-
-err_free_pdata:
-       /* If we have no platform_data, we allocated pdata dynamically.  */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(pdata);
-
-       return error;
-}
-
-static int gpio_keys_polled_remove(struct platform_device *pdev)
-{
-       struct gpio_keys_polled_dev *bdev = platform_get_drvdata(pdev);
-       const struct gpio_keys_platform_data *pdata = bdev->pdata;
-       int i;
-
-       input_unregister_polled_device(bdev->poll_dev);
-
-       for (i = 0; i < pdata->nbuttons; i++)
-               gpio_free(pdata->buttons[i].gpio);
-
-       input_free_polled_device(bdev->poll_dev);
-
-       /*
-        * If we had no platform_data, we allocated pdata dynamically and
-        * must free it here.
-        */
-       if (!dev_get_platdata(&pdev->dev))
-               kfree(pdata);
-
-       kfree(bdev);
-
-       return 0;
 }
 
 static struct platform_driver gpio_keys_polled_driver = {
        .probe  = gpio_keys_polled_probe,
-       .remove = gpio_keys_polled_remove,
        .driver = {
                .name   = DRV_NAME,
                .owner  = THIS_MODULE,
index 97ec335..8280cb1 100644 (file)
@@ -415,7 +415,7 @@ open_err:
 }
 
 #ifdef CONFIG_OF
-static struct of_device_id imx_keypad_of_match[] = {
+static const struct of_device_id imx_keypad_of_match[] = {
        { .compatible = "fsl,imx21-kpp", },
        { /* sentinel */ }
 };
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
new file mode 100644 (file)
index 0000000..758b487
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * STMicroelectronics Key Scanning driver
+ *
+ * Copyright (c) 2014 STMicroelectonics Ltd.
+ * Author: Stuart Menefy <stuart.menefy@st.com>
+ *
+ * Based on sh_keysc.c, copyright 2008 Magnus Damm
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/input/matrix_keypad.h>
+
+#define ST_KEYSCAN_MAXKEYS 16
+
+#define KEYSCAN_CONFIG_OFF             0x0
+#define KEYSCAN_CONFIG_ENABLE          0x1
+#define KEYSCAN_DEBOUNCE_TIME_OFF      0x4
+#define KEYSCAN_MATRIX_STATE_OFF       0x8
+#define KEYSCAN_MATRIX_DIM_OFF         0xc
+#define KEYSCAN_MATRIX_DIM_X_SHIFT     0x0
+#define KEYSCAN_MATRIX_DIM_Y_SHIFT     0x2
+
+struct st_keyscan {
+       void __iomem *base;
+       int irq;
+       struct clk *clk;
+       struct input_dev *input_dev;
+       unsigned long last_state;
+       unsigned int n_rows;
+       unsigned int n_cols;
+       unsigned int debounce_us;
+};
+
+static irqreturn_t keyscan_isr(int irq, void *dev_id)
+{
+       struct st_keyscan *keypad = dev_id;
+       unsigned short *keycode = keypad->input_dev->keycode;
+       unsigned long state, change;
+       int bit_nr;
+
+       state = readl(keypad->base + KEYSCAN_MATRIX_STATE_OFF) & 0xffff;
+       change = keypad->last_state ^ state;
+       keypad->last_state = state;
+
+       for_each_set_bit(bit_nr, &change, BITS_PER_LONG)
+               input_report_key(keypad->input_dev,
+                                keycode[bit_nr], state & BIT(bit_nr));
+
+       input_sync(keypad->input_dev);
+
+       return IRQ_HANDLED;
+}
+
+static int keyscan_start(struct st_keyscan *keypad)
+{
+       int error;
+
+       error = clk_enable(keypad->clk);
+       if (error)
+               return error;
+
+       writel(keypad->debounce_us * (clk_get_rate(keypad->clk) / 1000000),
+              keypad->base + KEYSCAN_DEBOUNCE_TIME_OFF);
+
+       writel(((keypad->n_cols - 1) << KEYSCAN_MATRIX_DIM_X_SHIFT) |
+              ((keypad->n_rows - 1) << KEYSCAN_MATRIX_DIM_Y_SHIFT),
+              keypad->base + KEYSCAN_MATRIX_DIM_OFF);
+
+       writel(KEYSCAN_CONFIG_ENABLE, keypad->base + KEYSCAN_CONFIG_OFF);
+
+       return 0;
+}
+
+static void keyscan_stop(struct st_keyscan *keypad)
+{
+       writel(0, keypad->base + KEYSCAN_CONFIG_OFF);
+
+       clk_disable(keypad->clk);
+}
+
+static int keyscan_open(struct input_dev *dev)
+{
+       struct st_keyscan *keypad = input_get_drvdata(dev);
+
+       return keyscan_start(keypad);
+}
+
+static void keyscan_close(struct input_dev *dev)
+{
+       struct st_keyscan *keypad = input_get_drvdata(dev);
+
+       keyscan_stop(keypad);
+}
+
+static int keypad_matrix_key_parse_dt(struct st_keyscan *keypad_data)
+{
+       struct device *dev = keypad_data->input_dev->dev.parent;
+       struct device_node *np = dev->of_node;
+       int error;
+
+       error = matrix_keypad_parse_of_params(dev, &keypad_data->n_rows,
+                                             &keypad_data->n_cols);
+       if (error) {
+               dev_err(dev, "failed to parse keypad params\n");
+               return error;
+       }
+
+       of_property_read_u32(np, "st,debounce-us", &keypad_data->debounce_us);
+
+       dev_dbg(dev, "n_rows=%d n_col=%d debounce=%d\n",
+               keypad_data->n_rows, keypad_data->n_cols,
+               keypad_data->debounce_us);
+
+       return 0;
+}
+
+static int keyscan_probe(struct platform_device *pdev)
+{
+       struct st_keyscan *keypad_data;
+       struct input_dev *input_dev;
+       struct resource *res;
+       int error;
+
+       if (!pdev->dev.of_node) {
+               dev_err(&pdev->dev, "no DT data present\n");
+               return -EINVAL;
+       }
+
+       keypad_data = devm_kzalloc(&pdev->dev, sizeof(*keypad_data),
+                                  GFP_KERNEL);
+       if (!keypad_data)
+               return -ENOMEM;
+
+       input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!input_dev) {
+               dev_err(&pdev->dev, "failed to allocate the input device\n");
+               return -ENOMEM;
+       }
+
+       input_dev->name = pdev->name;
+       input_dev->phys = "keyscan-keys/input0";
+       input_dev->dev.parent = &pdev->dev;
+       input_dev->open = keyscan_open;
+       input_dev->close = keyscan_close;
+
+       input_dev->id.bustype = BUS_HOST;
+
+       error = keypad_matrix_key_parse_dt(keypad_data);
+       if (error)
+               return error;
+
+       error = matrix_keypad_build_keymap(NULL, NULL,
+                                          keypad_data->n_rows,
+                                          keypad_data->n_cols,
+                                          NULL, input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to build keymap\n");
+               return error;
+       }
+
+       input_set_drvdata(input_dev, keypad_data);
+
+       keypad_data->input_dev = input_dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       keypad_data->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(keypad_data->base))
+               return PTR_ERR(keypad_data->base);
+
+       keypad_data->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(keypad_data->clk)) {
+               dev_err(&pdev->dev, "cannot get clock\n");
+               return PTR_ERR(keypad_data->clk);
+       }
+
+       error = clk_enable(keypad_data->clk);
+       if (error) {
+               dev_err(&pdev->dev, "failed to enable clock\n");
+               return error;
+       }
+
+       keyscan_stop(keypad_data);
+
+       keypad_data->irq = platform_get_irq(pdev, 0);
+       if (keypad_data->irq < 0) {
+               dev_err(&pdev->dev, "no IRQ specified\n");
+               return -EINVAL;
+       }
+
+       error = devm_request_irq(&pdev->dev, keypad_data->irq, keyscan_isr, 0,
+                                pdev->name, keypad_data);
+       if (error) {
+               dev_err(&pdev->dev, "failed to request IRQ\n");
+               return error;
+       }
+
+       error = input_register_device(input_dev);
+       if (error) {
+               dev_err(&pdev->dev, "failed to register input device\n");
+               return error;
+       }
+
+       platform_set_drvdata(pdev, keypad_data);
+
+       device_set_wakeup_capable(&pdev->dev, 1);
+
+       return 0;
+}
+
+static int keyscan_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct st_keyscan *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input = keypad->input_dev;
+
+       mutex_lock(&input->mutex);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(keypad->irq);
+       else if (input->users)
+               keyscan_stop(keypad);
+
+       mutex_unlock(&input->mutex);
+       return 0;
+}
+
+static int keyscan_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct st_keyscan *keypad = platform_get_drvdata(pdev);
+       struct input_dev *input = keypad->input_dev;
+       int retval = 0;
+
+       mutex_lock(&input->mutex);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(keypad->irq);
+       else if (input->users)
+               retval = keyscan_start(keypad);
+
+       mutex_unlock(&input->mutex);
+       return retval;
+}
+
+static SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops, keyscan_suspend, keyscan_resume);
+
+static const struct of_device_id keyscan_of_match[] = {
+       { .compatible = "st,sti-keyscan" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, keyscan_of_match);
+
+static struct platform_driver keyscan_device_driver = {
+       .probe          = keyscan_probe,
+       .driver         = {
+               .name   = "st-keyscan",
+               .pm     = &keyscan_dev_pm_ops,
+               .of_match_table = of_match_ptr(keyscan_of_match),
+       }
+};
+
+module_platform_driver(keyscan_device_driver);
+
+MODULE_AUTHOR("Stuart Menefy <stuart.menefy@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics keyscan device driver");
+MODULE_LICENSE("GPL");
index 74494a3..ad7abae 100644 (file)
@@ -296,6 +296,65 @@ static void tc3589x_keypad_close(struct input_dev *input)
        tc3589x_keypad_disable(keypad);
 }
 
+#ifdef CONFIG_OF
+static const struct tc3589x_keypad_platform_data *
+tc3589x_keypad_of_probe(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct tc3589x_keypad_platform_data *plat;
+       u32 cols, rows;
+       u32 debounce_ms;
+       int proplen;
+
+       if (!np)
+               return ERR_PTR(-ENODEV);
+
+       plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
+       if (!plat)
+               return ERR_PTR(-ENOMEM);
+
+       of_property_read_u32(np, "keypad,num-columns", &cols);
+       of_property_read_u32(np, "keypad,num-rows", &rows);
+       plat->kcol = (u8) cols;
+       plat->krow = (u8) rows;
+       if (!plat->krow || !plat->kcol ||
+            plat->krow > TC_KPD_ROWS || plat->kcol > TC_KPD_COLUMNS) {
+               dev_err(dev,
+                       "keypad columns/rows not properly specified (%ux%u)\n",
+                       plat->kcol, plat->krow);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (!of_get_property(np, "linux,keymap", &proplen)) {
+               dev_err(dev, "property linux,keymap not found\n");
+               return ERR_PTR(-ENOENT);
+       }
+
+       plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
+       plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup");
+
+       /* The custom delay format is ms/16 */
+       of_property_read_u32(np, "debounce-delay-ms", &debounce_ms);
+       if (debounce_ms)
+               plat->debounce_period = debounce_ms * 16;
+       else
+               plat->debounce_period = TC_KPD_DEBOUNCE_PERIOD;
+
+       plat->settle_time = TC_KPD_SETTLE_TIME;
+       /* FIXME: should be property of the IRQ resource? */
+       plat->irqtype = IRQF_TRIGGER_FALLING;
+
+       return plat;
+}
+#else
+static inline const struct tc3589x_keypad_platform_data *
+tc3589x_keypad_of_probe(struct device *dev)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
+
 static int tc3589x_keypad_probe(struct platform_device *pdev)
 {
        struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
@@ -306,8 +365,11 @@ static int tc3589x_keypad_probe(struct platform_device *pdev)
 
        plat = tc3589x->pdata->keypad;
        if (!plat) {
-               dev_err(&pdev->dev, "invalid keypad platform data\n");
-               return -EINVAL;
+               plat = tc3589x_keypad_of_probe(&pdev->dev);
+               if (IS_ERR(plat)) {
+                       dev_err(&pdev->dev, "invalid keypad platform data\n");
+                       return PTR_ERR(plat);
+               }
        }
 
        irq = platform_get_irq(pdev, 0);
index 5928ea7..2ff4425 100644 (file)
@@ -224,7 +224,7 @@ config INPUT_GP2A
 
 config INPUT_GPIO_BEEPER
        tristate "Generic GPIO Beeper support"
-       depends on OF_GPIO
+       depends on GPIOLIB
        help
          Say Y here if you have a beeper connected to a GPIO pin.
 
index b757435..8886af6 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Generic GPIO beeper driver
  *
- * Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2013-2014 Alexander Shiyan <shc_work@mail.ru>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -11,7 +11,8 @@
 
 #include <linux/input.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 
 
 struct gpio_beeper {
        struct work_struct      work;
-       int                     gpio;
-       bool                    active_low;
+       struct gpio_desc        *desc;
        bool                    beeping;
 };
 
 static void gpio_beeper_toggle(struct gpio_beeper *beep, bool on)
 {
-       gpio_set_value_cansleep(beep->gpio, on ^ beep->active_low);
+       gpiod_set_value_cansleep(beep->desc, on);
 }
 
 static void gpio_beeper_work(struct work_struct *work)
@@ -65,18 +65,16 @@ static void gpio_beeper_close(struct input_dev *input)
 static int gpio_beeper_probe(struct platform_device *pdev)
 {
        struct gpio_beeper *beep;
-       enum of_gpio_flags flags;
        struct input_dev *input;
-       unsigned long gflags;
        int err;
 
        beep = devm_kzalloc(&pdev->dev, sizeof(*beep), GFP_KERNEL);
        if (!beep)
                return -ENOMEM;
 
-       beep->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
-       if (!gpio_is_valid(beep->gpio))
-               return beep->gpio;
+       beep->desc = devm_gpiod_get(&pdev->dev, NULL);
+       if (IS_ERR(beep->desc))
+               return PTR_ERR(beep->desc);
 
        input = devm_input_allocate_device(&pdev->dev);
        if (!input)
@@ -94,10 +92,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_SND, SND_BELL);
 
-       beep->active_low = flags & OF_GPIO_ACTIVE_LOW;
-       gflags = beep->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
-
-       err = devm_gpio_request_one(&pdev->dev, beep->gpio, gflags, pdev->name);
+       err = gpiod_direction_output(beep->desc, 0);
        if (err)
                return err;
 
@@ -106,17 +101,19 @@ static int gpio_beeper_probe(struct platform_device *pdev)
        return input_register_device(input);
 }
 
-static struct of_device_id gpio_beeper_of_match[] = {
+#ifdef CONFIG_OF
+static const struct of_device_id gpio_beeper_of_match[] = {
        { .compatible = BEEPER_MODNAME, },
        { }
 };
 MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
+#endif
 
 static struct platform_driver gpio_beeper_platform_driver = {
        .driver = {
                .name           = BEEPER_MODNAME,
                .owner          = THIS_MODULE,
-               .of_match_table = gpio_beeper_of_match,
+               .of_match_table = of_match_ptr(gpio_beeper_of_match),
        },
        .probe  = gpio_beeper_probe,
 };
index 1cb8fda..c91e3d3 100644 (file)
@@ -92,15 +92,15 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
        bool pull_up;
 
        if (of_property_read_u32(pdev->dev.of_node, "debounce", &kpd_delay))
-               kpd_delay = 0;
+               kpd_delay = 15625;
 
-       pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
-
-       if (kpd_delay > 62500) {
+       if (kpd_delay > 62500 || kpd_delay == 0) {
                dev_err(&pdev->dev, "invalid power key trigger delay\n");
                return -EINVAL;
        }
 
+       pull_up = of_property_read_bool(pdev->dev.of_node, "pull-up");
+
        regmap = dev_get_regmap(pdev->dev.parent, NULL);
        if (!regmap) {
                dev_err(&pdev->dev, "failed to locate regmap for the device\n");
index 99b9e42..93558a1 100644 (file)
@@ -143,7 +143,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
 }
 
 #ifdef CONFIG_OF
-static struct of_device_id rotary_encoder_of_match[] = {
+static const struct of_device_id rotary_encoder_of_match[] = {
        { .compatible = "rotary-encoder", },
        { },
 };
index 77dc23b..6d26eec 100644 (file)
@@ -262,7 +262,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        struct vibra_info *info;
        int vddvibl_uV = 0;
        int vddvibr_uV = 0;
-       int ret;
+       int error;
 
        twl6040_core_node = of_find_node_by_name(twl6040_core_dev->of_node,
                                                 "vibra");
@@ -309,12 +309,12 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
 
        mutex_init(&info->mutex);
 
-       ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
-                                       twl6040_vib_irq_handler, 0,
-                                       "twl6040_irq_vib", info);
-       if (ret) {
-               dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
-               return ret;
+       error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+                                         twl6040_vib_irq_handler, 0,
+                                         "twl6040_irq_vib", info);
+       if (error) {
+               dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
+               return error;
        }
 
        info->supplies[0].supply = "vddvibl";
@@ -323,40 +323,40 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
         * When booted with Device tree the regulators are attached to the
         * parent device (twl6040 MFD core)
         */
-       ret = regulator_bulk_get(twl6040_core_dev, ARRAY_SIZE(info->supplies),
-                                info->supplies);
-       if (ret) {
-               dev_err(info->dev, "couldn't get regulators %d\n", ret);
-               return ret;
+       error = devm_regulator_bulk_get(twl6040_core_dev,
+                                       ARRAY_SIZE(info->supplies),
+                                       info->supplies);
+       if (error) {
+               dev_err(info->dev, "couldn't get regulators %d\n", error);
+               return error;
        }
 
        if (vddvibl_uV) {
-               ret = regulator_set_voltage(info->supplies[0].consumer,
-                                           vddvibl_uV, vddvibl_uV);
-               if (ret) {
+               error = regulator_set_voltage(info->supplies[0].consumer,
+                                             vddvibl_uV, vddvibl_uV);
+               if (error) {
                        dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
-                               ret);
-                       goto err_regulator;
+                               error);
+                       return error;
                }
        }
 
        if (vddvibr_uV) {
-               ret = regulator_set_voltage(info->supplies[1].consumer,
-                                           vddvibr_uV, vddvibr_uV);
-               if (ret) {
+               error = regulator_set_voltage(info->supplies[1].consumer,
+                                             vddvibr_uV, vddvibr_uV);
+               if (error) {
                        dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
-                               ret);
-                       goto err_regulator;
+                               error);
+                       return error;
                }
        }
 
        INIT_WORK(&info->play_work, vibra_play_work);
 
-       info->input_dev = input_allocate_device();
-       if (info->input_dev == NULL) {
+       info->input_dev = devm_input_allocate_device(&pdev->dev);
+       if (!info->input_dev) {
                dev_err(info->dev, "couldn't allocate input device\n");
-               ret = -ENOMEM;
-               goto err_regulator;
+               return -ENOMEM;
        }
 
        input_set_drvdata(info->input_dev, info);
@@ -367,44 +367,25 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
        info->input_dev->close = twl6040_vibra_close;
        __set_bit(FF_RUMBLE, info->input_dev->ffbit);
 
-       ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
-       if (ret < 0) {
+       error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
+       if (error) {
                dev_err(info->dev, "couldn't register vibrator to FF\n");
-               goto err_ialloc;
+               return error;
        }
 
-       ret = input_register_device(info->input_dev);
-       if (ret < 0) {
+       error = input_register_device(info->input_dev);
+       if (error) {
                dev_err(info->dev, "couldn't register input device\n");
-               goto err_iff;
+               return error;
        }
 
        platform_set_drvdata(pdev, info);
 
-       return 0;
-
-err_iff:
-       input_ff_destroy(info->input_dev);
-err_ialloc:
-       input_free_device(info->input_dev);
-err_regulator:
-       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-       return ret;
-}
-
-static int twl6040_vibra_remove(struct platform_device *pdev)
-{
-       struct vibra_info *info = platform_get_drvdata(pdev);
-
-       input_unregister_device(info->input_dev);
-       regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
-
        return 0;
 }
 
 static struct platform_driver twl6040_vibra_driver = {
        .probe          = twl6040_vibra_probe,
-       .remove         = twl6040_vibra_remove,
        .driver         = {
                .name   = "twl6040-vibra",
                .owner  = THIS_MODULE,
index effa9c5..ff9b65d 100644 (file)
@@ -53,7 +53,7 @@ config MOUSE_PS2_LOGIPS2PP
        default y
        depends on MOUSE_PS2
        help
-         Say Y here if you have a Logictech PS/2++ mouse connected to
+         Say Y here if you have a Logitech PS/2++ mouse connected to
          your system.
 
          If unsure, say Y.
index 17e01a8..98be824 100644 (file)
@@ -203,7 +203,7 @@ static int apbps2_of_remove(struct platform_device *of_dev)
        return 0;
 }
 
-static struct of_device_id apbps2_of_match[] = {
+static const struct of_device_id apbps2_of_match[] = {
        { .name = "GAISLER_APBPS2", },
        { .name = "01_060", },
        {}
index 5d2fe7e..d906f3e 100644 (file)
@@ -262,7 +262,7 @@ static int olpc_apsp_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id olpc_apsp_dt_ids[] = {
+static const struct of_device_id olpc_apsp_dt_ids[] = {
        { .compatible = "olpc,ap-sp", },
        {}
 };
index 4822c57..fb6678e 100644 (file)
@@ -1047,6 +1047,10 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
                        prox = data[0] & 0x01;
                        x = get_unaligned_le16(&data[1]);
                        y = get_unaligned_le16(&data[3]);
+               } else if (len == WACOM_PKGLEN_TPC1FG_B) {
+                       prox = data[2] & 0x01;
+                       x = get_unaligned_le16(&data[3]);
+                       y = get_unaligned_le16(&data[5]);
                } else {
                        prox = data[1] & 0x01;
                        x = le16_to_cpup((__le16 *)&data[2]);
@@ -2233,6 +2237,9 @@ static const struct wacom_features wacom_features_0x10E =
 static const struct wacom_features wacom_features_0x10F =
        { "Wacom ISDv4 10F",      WACOM_PKGLEN_MTTPC,     27760, 15694,  255,
          0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0x116 =
+       { "Wacom ISDv4 116",      WACOM_PKGLEN_GRAPHIRE,  26202, 16325,  255,
+         0, TABLETPCE, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 static const struct wacom_features wacom_features_0x4001 =
        { "Wacom ISDv4 4001",      WACOM_PKGLEN_MTTPC,     26202, 16325,  255,
          0, MTTPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -2447,6 +2454,7 @@ const struct usb_device_id wacom_ids[] = {
        { USB_DEVICE_WACOM(0x10D) },
        { USB_DEVICE_WACOM(0x10E) },
        { USB_DEVICE_WACOM(0x10F) },
+       { USB_DEVICE_WACOM(0x116) },
        { USB_DEVICE_WACOM(0x300) },
        { USB_DEVICE_WACOM(0x301) },
        { USB_DEVICE_DETAILED(0x302, USB_CLASS_HID, 0, 0) },
index f69c0eb..a066dc0 100644 (file)
@@ -22,6 +22,7 @@
 #define WACOM_PKGLEN_BBFUN      9
 #define WACOM_PKGLEN_INTUOS    10
 #define WACOM_PKGLEN_TPC1FG     5
+#define WACOM_PKGLEN_TPC1FG_B  10
 #define WACOM_PKGLEN_TPC2FG    14
 #define WACOM_PKGLEN_BBTOUCH   20
 #define WACOM_PKGLEN_BBTOUCH3  64
index 68edc9d..746d3c5 100644 (file)
@@ -858,7 +858,7 @@ config TOUCHSCREEN_TSC2007
 
 config TOUCHSCREEN_W90X900
        tristate "W90P910 touchscreen driver"
-       depends on HAVE_CLK
+       depends on ARCH_W90X900
        help
          Say Y here if you have a W90P910 based touchscreen.
 
@@ -897,6 +897,17 @@ config TOUCHSCREEN_STMPE
          To compile this driver as a module, choose M here: the
          module will be called stmpe-ts.
 
+config TOUCHSCREEN_SUN4I
+       tristate "Allwinner sun4i resistive touchscreen controller support"
+       depends on ARCH_SUNXI || COMPILE_TEST
+       depends on HWMON
+       help
+         This selects support for the resistive touchscreen controller
+         found on Allwinner sunxi SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sun4i-ts.
+
 config TOUCHSCREEN_SUR40
        tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
        depends on USB
index 4bc954b..71a9755 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR)      += pixcir_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)      += s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)       += st1232.o
 obj-$(CONFIG_TOUCHSCREEN_STMPE)                += stmpe-ts.o
+obj-$(CONFIG_TOUCHSCREEN_SUN4I)                += sun4i-ts.o
 obj-$(CONFIG_TOUCHSCREEN_SUR40)                += sur40.o
 obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC)        += ti_am335x_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)   += touchit213.o
index 6793c85..523865d 100644 (file)
@@ -210,11 +210,6 @@ static bool gpio3;
 module_param(gpio3, bool, 0);
 MODULE_PARM_DESC(gpio3, "If gpio3 is set to 1 AUX3 acts as GPIO3");
 
-/*
- * ad7877_read/write are only used for initial setup and for sysfs controls.
- * The main traffic is done using spi_async() in the interrupt handler.
- */
-
 static int ad7877_read(struct spi_device *spi, u16 reg)
 {
        struct ser_req *req;
index 7f8aa98..da201b8 100644 (file)
@@ -706,7 +706,7 @@ static void ads7846_read_state(struct ads7846 *ts)
                m = &ts->msg[msg_idx];
                error = spi_sync(ts->spi, m);
                if (error) {
-                       dev_err(&ts->spi->dev, "spi_async --> %d\n", error);
+                       dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
                        packet->tc.ignore = true;
                        return;
                }
index d3f9f6b..7f3c947 100644 (file)
@@ -679,7 +679,7 @@ static const struct i2c_device_id auo_pixcir_idtable[] = {
 MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
 
 #ifdef CONFIG_OF
-static struct of_device_id auo_pixcir_ts_dt_idtable[] = {
+static const struct of_device_id auo_pixcir_ts_dt_idtable[] = {
        { .compatible = "auo,auo_pixcir_ts" },
        {},
 };
index e6bcb13..c805784 100644 (file)
@@ -262,7 +262,7 @@ static int egalax_ts_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(egalax_ts_pm_ops, egalax_ts_suspend, egalax_ts_resume);
 
-static struct of_device_id egalax_ts_dt_ids[] = {
+static const struct of_device_id egalax_ts_dt_ids[] = {
        { .compatible = "eeti,egalax_ts" },
        { /* sentinel */ }
 };
index 2058253..bb47d34 100644 (file)
@@ -384,7 +384,7 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
 #endif
 
 #ifdef CONFIG_OF
-static struct of_device_id lpc32xx_tsc_of_match[] = {
+static const struct of_device_id lpc32xx_tsc_of_match[] = {
        { .compatible = "nxp,lpc3220-tsc", },
        { },
 };
index 8a598c0..9d83413 100644 (file)
@@ -570,7 +570,7 @@ static const struct i2c_device_id mms114_id[] = {
 MODULE_DEVICE_TABLE(i2c, mms114_id);
 
 #ifdef CONFIG_OF
-static struct of_device_id mms114_dt_match[] = {
+static const struct of_device_id mms114_dt_match[] = {
        { .compatible = "melfas,mms114" },
        { }
 };
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
new file mode 100644 (file)
index 0000000..2ba8260
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Allwinner sunxi resistive touchscreen controller driver
+ *
+ * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * The hwmon parts are based on work by Corentin LABBE which is:
+ * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * The sun4i-ts controller is capable of detecting a second touch, but when a
+ * second touch is present then the accuracy becomes so bad the reported touch
+ * location is not useable.
+ *
+ * The original android driver contains some complicated heuristics using the
+ * aprox. distance between the 2 touches to see if the user is making a pinch
+ * open / close movement, and then reports emulated multi-touch events around
+ * the last touch coordinate (as the dual-touch coordinates are worthless).
+ *
+ * These kinds of heuristics are just asking for trouble (and don't belong
+ * in the kernel). So this driver offers straight forward, reliable single
+ * touch functionality only.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define TP_CTRL0               0x00
+#define TP_CTRL1               0x04
+#define TP_CTRL2               0x08
+#define TP_CTRL3               0x0c
+#define TP_INT_FIFOC           0x10
+#define TP_INT_FIFOS           0x14
+#define TP_TPR                 0x18
+#define TP_CDAT                        0x1c
+#define TEMP_DATA              0x20
+#define TP_DATA                        0x24
+
+/* TP_CTRL0 bits */
+#define ADC_FIRST_DLY(x)       ((x) << 24) /* 8 bits */
+#define ADC_FIRST_DLY_MODE(x)  ((x) << 23)
+#define ADC_CLK_SEL(x)         ((x) << 22)
+#define ADC_CLK_DIV(x)         ((x) << 20) /* 3 bits */
+#define FS_DIV(x)              ((x) << 16) /* 4 bits */
+#define T_ACQ(x)               ((x) << 0) /* 16 bits */
+
+/* TP_CTRL1 bits */
+#define STYLUS_UP_DEBOUN(x)    ((x) << 12) /* 8 bits */
+#define STYLUS_UP_DEBOUN_EN(x) ((x) << 9)
+#define TOUCH_PAN_CALI_EN(x)   ((x) << 6)
+#define TP_DUAL_EN(x)          ((x) << 5)
+#define TP_MODE_EN(x)          ((x) << 4)
+#define TP_ADC_SELECT(x)       ((x) << 3)
+#define ADC_CHAN_SELECT(x)     ((x) << 0)  /* 3 bits */
+
+/* TP_CTRL2 bits */
+#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
+#define TP_MODE_SELECT(x)      ((x) << 26) /* 2 bits */
+#define PRE_MEA_EN(x)          ((x) << 24)
+#define PRE_MEA_THRE_CNT(x)    ((x) << 0) /* 24 bits */
+
+/* TP_CTRL3 bits */
+#define FILTER_EN(x)           ((x) << 2)
+#define FILTER_TYPE(x)         ((x) << 0)  /* 2 bits */
+
+/* TP_INT_FIFOC irq and fifo mask / control bits */
+#define TEMP_IRQ_EN(x)         ((x) << 18)
+#define OVERRUN_IRQ_EN(x)      ((x) << 17)
+#define DATA_IRQ_EN(x)         ((x) << 16)
+#define TP_DATA_XY_CHANGE(x)   ((x) << 13)
+#define FIFO_TRIG(x)           ((x) << 8)  /* 5 bits */
+#define DATA_DRQ_EN(x)         ((x) << 7)
+#define FIFO_FLUSH(x)          ((x) << 4)
+#define TP_UP_IRQ_EN(x)                ((x) << 1)
+#define TP_DOWN_IRQ_EN(x)      ((x) << 0)
+
+/* TP_INT_FIFOS irq and fifo status bits */
+#define TEMP_DATA_PENDING      BIT(18)
+#define FIFO_OVERRUN_PENDING   BIT(17)
+#define FIFO_DATA_PENDING      BIT(16)
+#define TP_IDLE_FLG            BIT(2)
+#define TP_UP_PENDING          BIT(1)
+#define TP_DOWN_PENDING                BIT(0)
+
+/* TP_TPR bits */
+#define TEMP_ENABLE(x)         ((x) << 16)
+#define TEMP_PERIOD(x)         ((x) << 0)  /* t = x * 256 * 16 / clkin */
+
+struct sun4i_ts_data {
+       struct device *dev;
+       struct input_dev *input;
+       void __iomem *base;
+       unsigned int irq;
+       bool ignore_fifo_data;
+       int temp_data;
+};
+
+static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
+{
+       u32 x, y;
+
+       if (reg_val & FIFO_DATA_PENDING) {
+               x = readl(ts->base + TP_DATA);
+               y = readl(ts->base + TP_DATA);
+               /* The 1st location reported after an up event is unreliable */
+               if (!ts->ignore_fifo_data) {
+                       input_report_abs(ts->input, ABS_X, x);
+                       input_report_abs(ts->input, ABS_Y, y);
+                       /*
+                        * The hardware has a separate down status bit, but
+                        * that gets set before we get the first location,
+                        * resulting in reporting a click on the old location.
+                        */
+                       input_report_key(ts->input, BTN_TOUCH, 1);
+                       input_sync(ts->input);
+               } else {
+                       ts->ignore_fifo_data = false;
+               }
+       }
+
+       if (reg_val & TP_UP_PENDING) {
+               ts->ignore_fifo_data = true;
+               input_report_key(ts->input, BTN_TOUCH, 0);
+               input_sync(ts->input);
+       }
+}
+
+static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
+{
+       struct sun4i_ts_data *ts = dev_id;
+       u32 reg_val;
+
+       reg_val  = readl(ts->base + TP_INT_FIFOS);
+
+       if (reg_val & TEMP_DATA_PENDING)
+               ts->temp_data = readl(ts->base + TEMP_DATA);
+
+       if (ts->input)
+               sun4i_ts_irq_handle_input(ts, reg_val);
+
+       writel(reg_val, ts->base + TP_INT_FIFOS);
+
+       return IRQ_HANDLED;
+}
+
+static int sun4i_ts_open(struct input_dev *dev)
+{
+       struct sun4i_ts_data *ts = input_get_drvdata(dev);
+
+       /* Flush, set trig level to 1, enable temp, data and up irqs */
+       writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
+               TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
+
+       return 0;
+}
+
+static void sun4i_ts_close(struct input_dev *dev)
+{
+       struct sun4i_ts_data *ts = input_get_drvdata(dev);
+
+       /* Deactivate all input IRQs */
+       writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sun4i_ts_data *ts = dev_get_drvdata(dev);
+
+       /* No temp_data until the first irq */
+       if (ts->temp_data == -1)
+               return -EAGAIN;
+
+       return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
+}
+
+static ssize_t show_temp_label(struct device *dev,
+                             struct device_attribute *devattr, char *buf)
+{
+       return sprintf(buf, "SoC temperature\n");
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
+
+static struct attribute *sun4i_ts_attrs[] = {
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp1_label.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(sun4i_ts);
+
+static int sun4i_ts_probe(struct platform_device *pdev)
+{
+       struct sun4i_ts_data *ts;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct device *hwmon;
+       int error;
+       bool ts_attached;
+
+       ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       ts->dev = dev;
+       ts->ignore_fifo_data = true;
+       ts->temp_data = -1;
+
+       ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
+       if (ts_attached) {
+               ts->input = devm_input_allocate_device(dev);
+               if (!ts->input)
+                       return -ENOMEM;
+
+               ts->input->name = pdev->name;
+               ts->input->phys = "sun4i_ts/input0";
+               ts->input->open = sun4i_ts_open;
+               ts->input->close = sun4i_ts_close;
+               ts->input->id.bustype = BUS_HOST;
+               ts->input->id.vendor = 0x0001;
+               ts->input->id.product = 0x0001;
+               ts->input->id.version = 0x0100;
+               ts->input->evbit[0] =  BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
+               __set_bit(BTN_TOUCH, ts->input->keybit);
+               input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
+               input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
+               input_set_drvdata(ts->input, ts);
+       }
+
+       ts->base = devm_ioremap_resource(dev,
+                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
+       if (IS_ERR(ts->base))
+               return PTR_ERR(ts->base);
+
+       ts->irq = platform_get_irq(pdev, 0);
+       error = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
+       if (error)
+               return error;
+
+       /*
+        * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
+        * t_acq = clkin / (16 * 64)
+        */
+       writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
+              ts->base + TP_CTRL0);
+
+       /*
+        * sensitive_adjust = 15 : max, which is not all that sensitive,
+        * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
+        */
+       writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
+              ts->base + TP_CTRL2);
+
+       /* Enable median filter, type 1 : 5/3 */
+       writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);
+
+       /* Enable temperature measurement, period 1953 (2 seconds) */
+       writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
+
+       /*
+        * Set stylus up debounce to aprox 10 ms, enable debounce, and
+        * finally enable tp mode.
+        */
+       writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
+              ts->base + TP_CTRL1);
+
+       hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
+                                                      ts, sun4i_ts_groups);
+       if (IS_ERR(hwmon))
+               return PTR_ERR(hwmon);
+
+       writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
+
+       if (ts_attached) {
+               error = input_register_device(ts->input);
+               if (error) {
+                       writel(0, ts->base + TP_INT_FIFOC);
+                       return error;
+               }
+       }
+
+       platform_set_drvdata(pdev, ts);
+       return 0;
+}
+
+static int sun4i_ts_remove(struct platform_device *pdev)
+{
+       struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
+
+       /* Explicit unregister to avoid open/close changing the imask later */
+       if (ts->input)
+               input_unregister_device(ts->input);
+
+       /* Deactivate all IRQs */
+       writel(0, ts->base + TP_INT_FIFOC);
+
+       return 0;
+}
+
+static const struct of_device_id sun4i_ts_of_match[] = {
+       { .compatible = "allwinner,sun4i-a10-ts", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
+
+static struct platform_driver sun4i_ts_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "sun4i-ts",
+               .of_match_table = of_match_ptr(sun4i_ts_of_match),
+       },
+       .probe  = sun4i_ts_probe,
+       .remove = sun4i_ts_remove,
+};
+
+module_platform_driver(sun4i_ts_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
index 550adcb..d981e49 100644 (file)
@@ -579,7 +579,7 @@ static int tsc2005_probe(struct spi_device *spi)
        int error;
 
        if (!pdata) {
-               dev_dbg(&spi->dev, "no platform data\n");
+               dev_err(&spi->dev, "no platform data\n");
                return -ENODEV;
        }
 
@@ -591,7 +591,7 @@ static int tsc2005_probe(struct spi_device *spi)
        max_p   = pdata->ts_pressure_max   ? : MAX_12BIT;
 
        if (spi->irq <= 0) {
-               dev_dbg(&spi->dev, "no irq\n");
+               dev_err(&spi->dev, "no irq\n");
                return -ENODEV;
        }
 
@@ -604,12 +604,13 @@ static int tsc2005_probe(struct spi_device *spi)
        if (error)
                return error;
 
-       ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-       input_dev = input_allocate_device();
-       if (!ts || !input_dev) {
-               error = -ENOMEM;
-               goto err_free_mem;
-       }
+       ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
+       if (!ts)
+               return -ENOMEM;
+
+       input_dev = devm_input_allocate_device(&spi->dev);
+       if (!input_dev)
+               return -ENOMEM;
 
        ts->spi = spi;
        ts->idev = input_dev;
@@ -649,12 +650,13 @@ static int tsc2005_probe(struct spi_device *spi)
        /* Ensure the touchscreen is off */
        tsc2005_stop_scan(ts);
 
-       error = request_threaded_irq(spi->irq, NULL, tsc2005_irq_thread,
-                                    IRQF_TRIGGER_RISING | IRQF_ONESHOT,
-                                    "tsc2005", ts);
+       error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+                                         tsc2005_irq_thread,
+                                         IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                         "tsc2005", ts);
        if (error) {
                dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
-               goto err_free_mem;
+               return error;
        }
 
        spi_set_drvdata(spi, ts);
@@ -662,7 +664,7 @@ static int tsc2005_probe(struct spi_device *spi)
        if (error) {
                dev_err(&spi->dev,
                        "Failed to create sysfs attributes, err: %d\n", error);
-               goto err_clear_drvdata;
+               return error;
        }
 
        error = input_register_device(ts->idev);
@@ -677,23 +679,12 @@ static int tsc2005_probe(struct spi_device *spi)
 
 err_remove_sysfs:
        sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
-err_clear_drvdata:
-       free_irq(spi->irq, ts);
-err_free_mem:
-       input_free_device(input_dev);
-       kfree(ts);
        return error;
 }
 
 static int tsc2005_remove(struct spi_device *spi)
 {
-       struct tsc2005 *ts = spi_get_drvdata(spi);
-
-       sysfs_remove_group(&ts->spi->dev.kobj, &tsc2005_attr_group);
-
-       free_irq(ts->spi->irq, ts);
-       input_unregister_device(ts->idev);
-       kfree(ts);
+       sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
 
        return 0;
 }
index 01d30ce..feea85b 100644 (file)
@@ -880,7 +880,7 @@ static struct i2c_device_id zforce_idtable[] = {
 MODULE_DEVICE_TABLE(i2c, zforce_idtable);
 
 #ifdef CONFIG_OF
-static struct of_device_id zforce_dt_idtable[] = {
+static const struct of_device_id zforce_dt_idtable[] = {
        { .compatible = "neonode,zforce" },
        {},
 };
index a7e977f..8b62246 100644 (file)
@@ -3,29 +3,53 @@
 
 struct device;
 
+/**
+ * struct gpio_keys_button - configuration parameters
+ * @code:              input event code (KEY_*, SW_*)
+ * @gpio:              %-1 if this key does not support gpio
+ * @active_low:                %true indicates that button is considered
+ *                     depressed when gpio is low
+ * @desc:              label that will be attached to button's gpio
+ * @type:              input event type (%EV_KEY, %EV_SW, %EV_ABS)
+ * @wakeup:            configure the button as a wake-up source
+ * @debounce_interval: debounce ticks interval in msecs
+ * @can_disable:       %true indicates that userspace is allowed to
+ *                     disable button via sysfs
+ * @value:             axis value for %EV_ABS
+ * @irq:               Irq number in case of interrupt keys
+ */
 struct gpio_keys_button {
-       /* Configuration parameters */
-       unsigned int code;      /* input event code (KEY_*, SW_*) */
-       int gpio;               /* -1 if this key does not support gpio */
+       unsigned int code;
+       int gpio;
        int active_low;
        const char *desc;
-       unsigned int type;      /* input event type (EV_KEY, EV_SW, EV_ABS) */
-       int wakeup;             /* configure the button as a wake-up source */
-       int debounce_interval;  /* debounce ticks interval in msecs */
+       unsigned int type;
+       int wakeup;
+       int debounce_interval;
        bool can_disable;
-       int value;              /* axis value for EV_ABS */
-       unsigned int irq;       /* Irq number in case of interrupt keys */
+       int value;
+       unsigned int irq;
 };
 
+/**
+ * struct gpio_keys_platform_data - platform data for gpio_keys driver
+ * @buttons:           pointer to array of &gpio_keys_button structures
+ *                     describing buttons attached to the device
+ * @nbuttons:          number of elements in @buttons array
+ * @poll_interval:     polling interval in msecs - for polling driver only
+ * @rep:               enable input subsystem auto repeat
+ * @enable:            platform hook for enabling the device
+ * @disable:           platform hook for disabling the device
+ * @name:              input device name
+ */
 struct gpio_keys_platform_data {
        struct gpio_keys_button *buttons;
        int nbuttons;
-       unsigned int poll_interval;     /* polling interval in msecs -
-                                          for polling driver only */
-       unsigned int rep:1;             /* enable input subsystem auto repeat */
+       unsigned int poll_interval;
+       unsigned int rep:1;
        int (*enable)(struct device *dev);
        void (*disable)(struct device *dev);
-       const char *name;               /* input device name */
+       const char *name;
 };
 
 #endif
index ce0b724..2465182 100644 (file)
@@ -48,9 +48,12 @@ struct input_polled_dev {
 
 /* private: */
        struct delayed_work work;
+
+       bool devres_managed;
 };
 
 struct input_polled_dev *input_allocate_polled_device(void);
+struct input_polled_dev *devm_input_allocate_polled_device(struct device *dev);
 void input_free_polled_device(struct input_polled_dev *dev);
 int input_register_polled_device(struct input_polled_dev *dev);
 void input_unregister_polled_device(struct input_polled_dev *dev);