Skip to contentSkip to conversation

Add generic GPIO-tilt driver

PATCH In review Heiko Stübner 4 participants 10 messages Nov 29, 2011

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 Add generic GPIO-tilt driver

There exist tilt switches that simply report their tilt-state via some gpios.

The number and orientation of their axes can vary depending on the switch used and the build of the device. Also two or more one-axis switches could be combined to provide multi-dimensional orientation.

One example of a device using such a switch is the family of Qisda ebook readers, where the switch provides information about the landscape / portrait orientation of the device. The example in Documentation/input/gpio-tilt.txt documents exactly this one-axis device.

---
changes since v2: use module_platform_driver changes since v1: address comments from Dmitry Torokhov
* bdev -> tdev
* report initial axis state during open and not during probe
* don't clone platform data and use the original instead

 Documentation/input/gpio-tilt.txt     |  103 ++++++++++++++++
 drivers/input/misc/Kconfig            |   14 ++
 drivers/input/misc/Makefile           |    1 +
 drivers/input/misc/gpio_tilt_polled.c |  214 +++++++++++++++++++++++++++++++++
 include/linux/gpio_tilt.h             |   73 +++++++++++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/input/gpio-tilt.txt
 create mode 100644 drivers/input/misc/gpio_tilt_polled.c
 create mode 100644 include/linux/gpio_tilt.h
Documentation/input/gpio-tilt.txt new file +103 -0
new file mode 100644
index 0000000..06d60c3
@@ -0,0 +1,103 @@
+Driver for tilt-switches connected via GPIOs
+============================================
+
+Generic driver to read data from tilt switches connected via gpios.
+Orientation can be provided by one or more than one tilt switches,
+i.e. each tilt switch providing one axis, and the number of axes
+is also not limited.
+
+
+Data structures:
+----------------
+
+The array of struct gpio in the gpios field is used to list the gpios
+that represent the current tilt state.
+
+The array of struct gpio_tilt_axis describes the axes that are reported
+to the input system. The values set therein are used for the
+input_set_abs_params calls needed to init the axes.
+
+The array of struct gpio_tilt_state maps gpio states to the corresponding
+values to report. The gpio state is represented as a bitfield where the
+bit-index corresponds to the index of the gpio in the struct gpio array.
+In the same manner the values stored in the axes array correspond to
+the elements of the gpio_tilt_axis-array.
+
+
+Example:
+--------
+
+Example configuration for a single TS1003 tilt switch that rotates around
+one axis in 4 steps and emitts the current tilt via two GPIOs.
+
+static int sg060_tilt_enable(struct device *dev) {
+	/* code to enable the sensors */
+};
+
+static void sg060_tilt_disable(struct device *dev) {
+	/* code to disable the sensors */
+};
+
+static struct gpio sg060_tilt_gpios[] = {
+	{ SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
+	{ SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
+};
+
+static struct gpio_tilt_state sg060_tilt_states[] = {
+	{
+		.gpios = (0 << 1) | (0 << 0),
+		.axes = (int[]) {
+			0,
+		},
+	}, {
+		.gpios = (0 << 1) | (1 << 0),
+		.axes = (int[]) {
+			1, /* 90 degrees */
+		},
+	}, {
+		.gpios = (1 << 1) | (1 << 0),
+		.axes = (int[]) {
+			2, /* 180 degrees */
+		},
+	}, {
+		.gpios = (1 << 1) | (0 << 0),
+		.axes = (int[]) {
+			3, /* 270 degrees */
+		},
+	},
+};
+
+static struct gpio_tilt_axis sg060_tilt_axes[] = {
+	{
+		.axis = ABS_RY,
+		.min = 0,
+		.max = 3,
+		.fuzz = 0,
+		.flat = 0,
+	},
+};
+
+static struct gpio_tilt_platform_data sg060_tilt_pdata= {
+	.gpios = sg060_tilt_gpios,
+	.nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
+
+	.axes = sg060_tilt_axes,
+	.nr_axes = ARRAY_SIZE(sg060_tilt_axes),
+
+	.states = sg060_tilt_states,
+	.nr_states = ARRAY_SIZE(sg060_tilt_states),
+
+	.debounce_interval = 100,
+
+	.poll_interval = 1000,
+	.enable = sg060_tilt_enable,
+	.disable = sg060_tilt_disable,
+};
+
+static struct platform_device sg060_device_tilt = {
+	.name = "gpio-tilt-polled",
+	.id = -1,
+	.dev = {
+		.platform_data = &sg060_tilt_pdata,
+	},
+};
drivers/input/misc/Kconfig +14 -0
index 22d875f..e53b443 100644
@@ -179,6 +179,20 @@ config INPUT_APANEL
 	 To compile this driver as a module, choose M here: the module will
 	 be called apanel.
 
+config INPUT_GPIO_TILT_POLLED
+	tristate "Polled GPIO tilt switch"
+	depends on GENERIC_GPIO
+	select INPUT_POLLDEV
+	help
+	  This driver implements support for tilt switches connected
+	  to GPIO pins that are not capable of generating interrupts.
+
+	  The list of gpios to use and the mapping of their states
+	  to specific angles is done via platform data.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gpio_tilt_polled.
+
 config INPUT_IXP4XX_BEEPER
 	tristate "IXP4XX Beeper support"
 	depends on ARCH_IXP4XX
drivers/input/misc/Makefile +1 -0
index a244fc6..90070c1 100644
@@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C)		+= cma3000_d0x_i2c.o
 obj-$(CONFIG_INPUT_COBALT_BTNS)		+= cobalt_btns.o
 obj-$(CONFIG_INPUT_DM355EVM)		+= dm355evm_keys.o
 obj-$(CONFIG_HP_SDC_RTC)		+= hp_sdc_rtc.o
+obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)	+= gpio_tilt_polled.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)	+= ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)	+= keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)		+= kxtj9.o
drivers/input/misc/gpio_tilt_polled.c new file +214 -0

214 lines not on this page · raw message

include/linux/gpio_tilt.h new file +73 -0

73 lines not on this page · raw message

Signature · 1 line
1.7.5.4
#1 lore raw

Hi Heiko,

Quoted 220 lines · Heiko Stübner

There exist tilt switches that simply report their tilt-state via some gpios.

The number and orientation of their axes can vary depending on the switch used and the build of the device. Also two or more one-axis switches could be combined to provide multi-dimensional orientation.

One example of a device using such a switch is the family of Qisda ebook readers, where the switch provides information about the landscape / portrait orientation of the device. The example in Documentation/input/gpio-tilt.txt documents exactly this one-axis device.

---
changes since v2: use module_platform_driver changes since v1: address comments from Dmitry Torokhov
* bdev -> tdev
* report initial axis state during open and not during probe
* don't clone platform data and use the original instead

 Documentation/input/gpio-tilt.txt     |  103 ++++++++++++++++ drivers/input/misc/Kconfig            |   14 ++ drivers/input/misc/Makefile           |    1 + drivers/input/misc/gpio_tilt_polled.c |  214 +++++++++++++++++++++++++++++++++ include/linux/gpio_tilt.h             |   73 +++++++++++

 5 files changed, 405 insertions(+), 0 deletions(-)

 create mode 100644 Documentation/input/gpio-tilt.txt create mode 100644 drivers/input/misc/gpio_tilt_polled.c create mode 100644 include/linux/gpio_tilt.h

Documentation/input/gpio-tilt.txt new file +103 -0
new file mode 100644
index 0000000..06d60c3
@@ -0,0 +1,103 @@
+Driver for tilt-switches connected via GPIOs
+============================================
+
+Generic driver to read data from tilt switches connected via gpios.
+Orientation can be provided by one or more than one tilt switches,
+i.e. each tilt switch providing one axis, and the number of axes
+is also not limited.
+
+
+Data structures:
+----------------
+
+The array of struct gpio in the gpios field is used to list the gpios
+that represent the current tilt state.
+
+The array of struct gpio_tilt_axis describes the axes that are reported
+to the input system. The values set therein are used for the
+input_set_abs_params calls needed to init the axes.
+
+The array of struct gpio_tilt_state maps gpio states to the corresponding
+values to report. The gpio state is represented as a bitfield where the
+bit-index corresponds to the index of the gpio in the struct gpio array.
+In the same manner the values stored in the axes array correspond to
+the elements of the gpio_tilt_axis-array.
+
+
+Example:
+--------
+
+Example configuration for a single TS1003 tilt switch that rotates around
+one axis in 4 steps and emitts the current tilt via two GPIOs.
+
+static int sg060_tilt_enable(struct device *dev) {
+       /* code to enable the sensors */
+};
+
+static void sg060_tilt_disable(struct device *dev) {
+       /* code to disable the sensors */
+};
+
+static struct gpio sg060_tilt_gpios[] = {
+       { SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
+       { SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
+};
+
+static struct gpio_tilt_state sg060_tilt_states[] = {
+       {
+               .gpios = (0 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       0,
+               },
+       }, {
+               .gpios = (0 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       1, /* 90 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       2, /* 180 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       3, /* 270 degrees */
+               },
+       },
+};
+
+static struct gpio_tilt_axis sg060_tilt_axes[] = {
+       {
+               .axis = ABS_RY,
+               .min = 0,
+               .max = 3,
+               .fuzz = 0,
+               .flat = 0,
+       },
+};
+
+static struct gpio_tilt_platform_data sg060_tilt_pdata= {
+       .gpios = sg060_tilt_gpios,
+       .nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
+
+       .axes = sg060_tilt_axes,
+       .nr_axes = ARRAY_SIZE(sg060_tilt_axes),
+
+       .states = sg060_tilt_states,
+       .nr_states = ARRAY_SIZE(sg060_tilt_states),
+
+       .debounce_interval = 100,
+
+       .poll_interval = 1000,
+       .enable = sg060_tilt_enable,
+       .disable = sg060_tilt_disable,
+};
+
+static struct platform_device sg060_device_tilt = {
+       .name = "gpio-tilt-polled",
+       .id = -1,
+       .dev = {
+               .platform_data = &sg060_tilt_pdata,
+       },
+};
drivers/input/misc/Kconfig +0 -0
index 22d875f..e53b443 100644
@@ -179,6 +179,20 @@ config INPUT_APANEL

        To compile this driver as a module, choose M here: the module will be called apanel.

drivers/input/misc/Kconfig +14 -0
+config INPUT_GPIO_TILT_POLLED
+       tristate "Polled GPIO tilt switch"
+       depends on GENERIC_GPIO
+       select INPUT_POLLDEV
+       help
+         This driver implements support for tilt switches connected
+         to GPIO pins that are not capable of generating interrupts.
+
+         The list of gpios to use and the mapping of their states
+         to specific angles is done via platform data.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gpio_tilt_polled.
+

 config INPUT_IXP4XX_BEEPER
       tristate "IXP4XX Beeper support"
       depends on ARCH_IXP4XX

drivers/input/misc/Makefile +0 -0
index a244fc6..90070c1 100644
@@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C)               += cma3000_d0x_i2c.o

 obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o +obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)   += gpio_tilt_polled.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9)              += kxtj9.o

drivers/input/misc/gpio_tilt_polled.c new file +39 -0
new file mode 100644
index 0000000..ebc3f08
@@ -0,0 +1,214 @@
+/*
+ *  Driver for tilt switches connected via GPIO lines
+ *  not capable of generating interrupts
+ *
+ *  Copyright (C) 2011 Heiko Stuebner <[email protected]>
+ *
+ *  based on: /drivers/input/keyboard/gpio_keys_polled.c
+ *
+ *  Copyright (C) 2007-2010 Gabor Juhos <[email protected]>
+ *  Copyright (C) 2010 Nuno Goncalves <[email protected]>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_tilt.h>
+
+#define DRV_NAME       "gpio-tilt-polled"
+
+struct gpio_tilt_polled_dev {
+       struct input_polled_dev *poll_dev;
+       struct device *dev;
+       struct gpio_tilt_platform_data *pdata;
+
+       int last_state;
+
+       int threshold;
+       int count;
+};

drivers/input/misc/gpio_tilt_polled.c line 49

Quoted 10 lines
drivers/input/misc/gpio_tilt_polled.c new file +10 -0
+
+static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+       struct input_dev *input = dev->input;
+       struct gpio_tilt_state *tilt_state = NULL;
+       int state, i;
+
+       if (tdev->count < tdev->threshold) {

Nitpick : the braces are not necessary.

Quoted 50 lines
drivers/input/misc/gpio_tilt_polled.c new file +50 -0
+               tdev->count++;
+       } else {
+               state = 0;
+               for (i = 0; i < pdata->nr_gpios; i++)
+                       state |= (!!gpio_get_value(pdata->gpios[i].gpio) << i);
+
+               if (state != tdev->last_state) {
+                       for (i = 0; i < pdata->nr_states; i++)
+                               if (pdata->states[i].gpios == state)
+                                       tilt_state = &pdata->states[i];
+
+                       if (tilt_state) {
+                               for (i = 0; i < pdata->nr_axes; i++)
+                                       input_report_abs(input,
+                                                        pdata->axes[i].axis,
+                                                        tilt_state->axes[i]);
+
+                               input_sync(input);
+                       }
+
+                       tdev->count = 0;
+                       tdev->last_state = state;
+               }
+       }
+}
+
+static void gpio_tilt_polled_open(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->enable)
+               pdata->enable(tdev->dev);
+
+       /* report initial state of the axes */
+       tdev->last_state = -1;
+       tdev->count = tdev->threshold;
+       gpio_tilt_polled_poll(tdev->poll_dev);
+}
+
+static void gpio_tilt_polled_close(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->disable)
+               pdata->disable(tdev->dev);
+}
+
+static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev)

drivers/input/misc/gpio_tilt_polled.c line 109

Quoted 10 lines
drivers/input/misc/gpio_tilt_polled.c new file +10 -0
+{
+       struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct gpio_tilt_polled_dev *tdev;
+       struct input_polled_dev *poll_dev;
+       struct input_dev *input;
+       int error, i;
+
+       if (!pdata || !pdata->poll_interval)
+               return -EINVAL;

Could we have a default poll interval if passed 0 ? Feel free to ignore if you feel otherwise.

Quoted 187 lines
drivers/input/misc/gpio_tilt_polled.c new file +105 -0
+
+       tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
+       if (!tdev) {
+               dev_err(dev, "no memory for private data\n");
+               return -ENOMEM;
+       }
+
+       error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
+       if (error) {
+               dev_err(dev,
+                  "Could not request tilt GPIOs: %d\n", error);
+               goto err_free_tdev;
+       }
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               dev_err(dev, "no memory for polled device\n");
+               error = -ENOMEM;
+               goto err_free_gpios;
+       }
+
+       poll_dev->private = tdev;
+       poll_dev->poll = gpio_tilt_polled_poll;
+       poll_dev->poll_interval = pdata->poll_interval;
+       poll_dev->open = gpio_tilt_polled_open;
+       poll_dev->close = gpio_tilt_polled_close;
+
+       input = poll_dev->input;
+
+       input->name = pdev->name;
+       input->phys = DRV_NAME"/input0";
+       input->dev.parent = &pdev->dev;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       __set_bit(EV_ABS, input->evbit);
+       for (i = 0; i < pdata->nr_axes; i++) {
+               input_set_abs_params(input, pdata->axes[i].axis,
+                                    pdata->axes[i].min, pdata->axes[i].max,
+                                    pdata->axes[i].fuzz, pdata->axes[i].flat);
+       }
+
+       tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
+                                      pdata->poll_interval);
+
+       tdev->poll_dev = poll_dev;
+       tdev->dev = dev;
+       tdev->pdata = pdata;
+
+       error = input_register_polled_device(poll_dev);
+       if (error) {
+               dev_err(dev, "unable to register polled device, err=%d\n",
+                       error);
+               goto err_free_polldev;
+       }
+
+       platform_set_drvdata(pdev, tdev);
+
+       return 0;
+
+err_free_polldev:
+       input_free_polled_device(poll_dev);
+err_free_gpios:
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+err_free_tdev:
+       kfree(tdev);
+
+       return error;
+}
+
+static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev)
+{
+       struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_polled_device(tdev->poll_dev);
+       input_free_polled_device(tdev->poll_dev);
+
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+
+       kfree(tdev);
+
+       return 0;
+}
+
+static struct platform_driver gpio_tilt_polled_driver = {
+       .probe  = gpio_tilt_polled_probe,
+       .remove = __devexit_p(gpio_tilt_polled_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(gpio_tilt_polled_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <[email protected]>");
+MODULE_DESCRIPTION("Polled GPIO tilt driver");
+MODULE_ALIAS("platform:" DRV_NAME);
include/linux/gpio_tilt.h new file +73 -1
new file mode 100644
index 0000000..809fe93
@@ -0,0 +1,73 @@
+#ifndef _GPIO_TILT_H
+#define _GPIO_TILT_H
+
+/**
+ * struct gpio_tilt_axis - Axis used by the tilt switch
+ * @axis:              Constant describing the axis, e.g. ABS_X
+ * @min:               minimum value for abs_param
+ * @max:               maximum value for abs_param
+ * @fuzz:              fuzz value for abs_param
+ * @flat:              flat value for abs_param
+ */
+struct gpio_tilt_axis {
+       int axis;
+       int min;
+       int max;
+       int fuzz;
+       int flat;
+};
+
+/**
+ * struct gpio_tilt_state - state description
+ * @gpios:             bitfield of gpio target-states for the value
+ * @axes:              array containing the axes settings for the gpio state
+ *                     The array indizes must correspond to the axes defined
+ *                     in platform_data
+ *
+ * This structure describes a supported axis settings
+ * and the necessary gpio-state which represent it.
+ *
+ * The n-th bit in the bitfield describes the state of the n-th GPIO
+ * from the gpios-array defined in gpio_regulator_config below.
+ */
+struct gpio_tilt_state {
+       int gpios;
+       int *axes;
+};
+
+/**
+ * struct gpio_tilt_platform_data
+ * @gpios:             Array containing the gpios determining the tilt state
+ * @nr_gpios:          Number of gpios
+ * @axes:              Array of gpio_tilt_axis descriptions
+ * @nr_axes:           Number of axes
+ * @states:            Array of gpio_tilt_state entries describing
+ *                     the gpio state for specific tilts
+ * @nr_states:         Number of states available
+ * @debounce_interval: debounce ticks interval in msecs
+ * @poll_interval:     polling interval in msecs - for polling driver only
+ * @enable:            callback to enable the tilt switch
+ * @disable:           callback to disable the tilt switch
+ *
+ * This structure contains gpio-tilt-switch configuration
+ * information that must be passed by platform code to the
+ * gpio-tilt input driver.
+ */
+struct gpio_tilt_platform_data {
+       struct gpio *gpios;
+       int nr_gpios;
+
+       struct gpio_tilt_axis *axes;
+       int nr_axes;
+
+       struct gpio_tilt_state *states;
+       int nr_states;
+
+       int debounce_interval;
+
+       unsigned int poll_interval;
+       int (*enable)(struct device *dev);
+       void (*disable)(struct device *dev);
+};
+
+#endif
--

1.7.5.4

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#2 lore raw

Hi Shubhrajyoti,

Am Dienstag, 29. November 2011, 15:59:29 schrieb Shubhrajyoti Datta:

Quoted 229 lines

Hi Heiko,

Quoted 226 lines · Heiko Stübner

There exist tilt switches that simply report their tilt-state via some gpios.

The number and orientation of their axes can vary depending on the switch used and the build of the device. Also two or more one-axis switches could be combined to provide multi-dimensional orientation.

One example of a device using such a switch is the family of Qisda ebook readers, where the switch provides information about the landscape / portrait orientation of the device. The example in Documentation/input/gpio-tilt.txt documents exactly this one-axis device.

---
changes since v2: use module_platform_driver changes since v1: address comments from Dmitry Torokhov
* bdev -> tdev
* report initial axis state during open and not during probe
* don't clone platform data and use the original instead

 Documentation/input/gpio-tilt.txt     |  103 ++++++++++++++++
 drivers/input/misc/Kconfig            |   14 ++
 drivers/input/misc/Makefile           |    1 +
 drivers/input/misc/gpio_tilt_polled.c |  214
+++++++++++++++++++++++++++++++++ include/linux/gpio_tilt.h            
|   73 +++++++++++
 5 files changed, 405 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/input/gpio-tilt.txt
 create mode 100644 drivers/input/misc/gpio_tilt_polled.c
 create mode 100644 include/linux/gpio_tilt.h
(quoted diff) +0 -0

b/Documentation/input/gpio-tilt.txt new file mode 100644 index 0000000..06d60c3

Documentation/input/gpio-tilt.txt new file +20 -0
@@ -0,0 +1,103 @@
+Driver for tilt-switches connected via GPIOs
+============================================
+
+Generic driver to read data from tilt switches connected via gpios.
+Orientation can be provided by one or more than one tilt switches,
+i.e. each tilt switch providing one axis, and the number of axes
+is also not limited.
+
+
+Data structures:
+----------------
+
+The array of struct gpio in the gpios field is used to list the gpios
+that represent the current tilt state.
+
+The array of struct gpio_tilt_axis describes the axes that are reported
+to the input system. The values set therein are used for the
+input_set_abs_params calls needed to init the axes.
+
+The array of struct gpio_tilt_state maps gpio states to the

corresponding +values to report. The gpio state is represented as a bitfield where the +bit-index corresponds to the index of the gpio in the struct gpio array. +In the same manner the values stored in the axes array correspond to +the elements of the gpio_tilt_axis-array.

Documentation/input/gpio-tilt.txt new file +6 -0
+
+
+Example:
+--------
+
+Example configuration for a single TS1003 tilt switch that rotates

around +one axis in 4 steps and emitts the current tilt via two GPIOs.

Documentation/input/gpio-tilt.txt new file +72 -0
+
+static int sg060_tilt_enable(struct device *dev) {
+       /* code to enable the sensors */
+};
+
+static void sg060_tilt_disable(struct device *dev) {
+       /* code to disable the sensors */
+};
+
+static struct gpio sg060_tilt_gpios[] = {
+       { SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
+       { SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
+};
+
+static struct gpio_tilt_state sg060_tilt_states[] = {
+       {
+               .gpios = (0 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       0,
+               },
+       }, {
+               .gpios = (0 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       1, /* 90 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       2, /* 180 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       3, /* 270 degrees */
+               },
+       },
+};
+
+static struct gpio_tilt_axis sg060_tilt_axes[] = {
+       {
+               .axis = ABS_RY,
+               .min = 0,
+               .max = 3,
+               .fuzz = 0,
+               .flat = 0,
+       },
+};
+
+static struct gpio_tilt_platform_data sg060_tilt_pdata= {
+       .gpios = sg060_tilt_gpios,
+       .nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
+
+       .axes = sg060_tilt_axes,
+       .nr_axes = ARRAY_SIZE(sg060_tilt_axes),
+
+       .states = sg060_tilt_states,
+       .nr_states = ARRAY_SIZE(sg060_tilt_states),
+
+       .debounce_interval = 100,
+
+       .poll_interval = 1000,
+       .enable = sg060_tilt_enable,
+       .disable = sg060_tilt_disable,
+};
+
+static struct platform_device sg060_device_tilt = {
+       .name = "gpio-tilt-polled",
+       .id = -1,
+       .dev = {
+               .platform_data = &sg060_tilt_pdata,
+       },
+};
drivers/input/misc/Kconfig +0 -0
index 22d875f..e53b443 100644
@@ -179,6 +179,20 @@ config INPUT_APANEL
        To compile this driver as a module, choose M here: the module

will be called apanel.

drivers/input/misc/Kconfig +14 -0
+config INPUT_GPIO_TILT_POLLED
+       tristate "Polled GPIO tilt switch"
+       depends on GENERIC_GPIO
+       select INPUT_POLLDEV
+       help
+         This driver implements support for tilt switches connected
+         to GPIO pins that are not capable of generating interrupts.
+
+         The list of gpios to use and the mapping of their states
+         to specific angles is done via platform data.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gpio_tilt_polled.
+
 config INPUT_IXP4XX_BEEPER
       tristate "IXP4XX Beeper support"
       depends on ARCH_IXP4XX
drivers/input/misc/Makefile +0 -0
index a244fc6..90070c1 100644
@@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C)               +=

cma3000_d0x_i2c.o obj-$(CONFIG_INPUT_COBALT_BTNS) +=
cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o

drivers/input/misc/Makefile +1 -0
+obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)   += gpio_tilt_polled.o
 obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o
 obj-$(CONFIG_INPUT_KXTJ9)              += kxtj9.o
(quoted diff) +0 -0

b/drivers/input/misc/gpio_tilt_polled.c new file mode 100644 index 0000000..ebc3f08

drivers/input/misc/gpio_tilt_polled.c new file +43 -0
@@ -0,0 +1,214 @@
+/*
+ *  Driver for tilt switches connected via GPIO lines
+ *  not capable of generating interrupts
+ *
+ *  Copyright (C) 2011 Heiko Stuebner <[email protected]>
+ *
+ *  based on: /drivers/input/keyboard/gpio_keys_polled.c
+ *
+ *  Copyright (C) 2007-2010 Gabor Juhos <[email protected]>
+ *  Copyright (C) 2010 Nuno Goncalves <[email protected]>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_tilt.h>
+
+#define DRV_NAME       "gpio-tilt-polled"
+
+struct gpio_tilt_polled_dev {
+       struct input_polled_dev *poll_dev;
+       struct device *dev;
+       struct gpio_tilt_platform_data *pdata;
+
+       int last_state;
+
+       int threshold;
+       int count;
+};
+
+static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
Quoted 8 lines

drivers/input/misc/gpio_tilt_polled.c line 49

Quoted 6 lines
drivers/input/misc/gpio_tilt_polled.c new file +6 -0
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+       struct input_dev *input = dev->input;
+       struct gpio_tilt_state *tilt_state = NULL;
+       int state, i;
+
+       if (tdev->count < tdev->threshold) {

Nitpick : the braces are not necessary.

hmm ... for me it's easier to read if the style of the braces does not change between if and else, i.e. both with or without braces.
And the kernel CodingStyle-file seems also to be in my favor ;-) [starting from line 169].

Quoted 55 lines
Quoted 55 lines
drivers/input/misc/gpio_tilt_polled.c new file +5 -0
+               tdev->count++;
+       } else {
+               state = 0;
+               for (i = 0; i < pdata->nr_gpios; i++)
+                       state |= (!!gpio_get_value(pdata->gpios[i].gpio)

<< i); +

drivers/input/misc/gpio_tilt_polled.c new file +42 -0
+               if (state != tdev->last_state) {
+                       for (i = 0; i < pdata->nr_states; i++)
+                               if (pdata->states[i].gpios == state)
+                                       tilt_state = &pdata->states[i];
+
+                       if (tilt_state) {
+                               for (i = 0; i < pdata->nr_axes; i++)
+                                       input_report_abs(input,
+                                                      
 pdata->axes[i].axis, +                                                
       tilt_state->axes[i]); +
+                               input_sync(input);
+                       }
+
+                       tdev->count = 0;
+                       tdev->last_state = state;
+               }
+       }
+}
+
+static void gpio_tilt_polled_open(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->enable)
+               pdata->enable(tdev->dev);
+
+       /* report initial state of the axes */
+       tdev->last_state = -1;
+       tdev->count = tdev->threshold;
+       gpio_tilt_polled_poll(tdev->poll_dev);
+}
+
+static void gpio_tilt_polled_close(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->disable)
+               pdata->disable(tdev->dev);
+}
+
+static int __devinit gpio_tilt_polled_probe(struct platform_device

*pdev) +{

drivers/input/misc/gpio_tilt_polled.c new file +4 -0
+       struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct gpio_tilt_polled_dev *tdev;
+       struct input_polled_dev *poll_dev;
Quoted 8 lines

drivers/input/misc/gpio_tilt_polled.c line 109

Quoted 5 lines
drivers/input/misc/gpio_tilt_polled.c new file +5 -0
+       struct input_dev *input;
+       int error, i;
+
+       if (!pdata || !pdata->poll_interval)
+               return -EINVAL;

Could we have a default poll interval if passed 0 ? Feel free to ignore if you feel otherwise.

For me either way is fine but I'm not sure what would be a generic enough default value for most cases (500, 1000 ? ).

Quoted 187 lines
Quoted 187 lines
drivers/input/misc/gpio_tilt_polled.c new file +42 -0
+
+       tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
+       if (!tdev) {
+               dev_err(dev, "no memory for private data\n");
+               return -ENOMEM;
+       }
+
+       error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
+       if (error) {
+               dev_err(dev,
+                  "Could not request tilt GPIOs: %d\n", error);
+               goto err_free_tdev;
+       }
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               dev_err(dev, "no memory for polled device\n");
+               error = -ENOMEM;
+               goto err_free_gpios;
+       }
+
+       poll_dev->private = tdev;
+       poll_dev->poll = gpio_tilt_polled_poll;
+       poll_dev->poll_interval = pdata->poll_interval;
+       poll_dev->open = gpio_tilt_polled_open;
+       poll_dev->close = gpio_tilt_polled_close;
+
+       input = poll_dev->input;
+
+       input->name = pdev->name;
+       input->phys = DRV_NAME"/input0";
+       input->dev.parent = &pdev->dev;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       __set_bit(EV_ABS, input->evbit);
+       for (i = 0; i < pdata->nr_axes; i++) {
+               input_set_abs_params(input, pdata->axes[i].axis,
+                                    pdata->axes[i].min,

pdata->axes[i].max, +
pdata->axes[i].fuzz, pdata->axes[i].flat); + }

drivers/input/misc/gpio_tilt_polled.c new file +11 -0
+
+       tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
+                                      pdata->poll_interval);
+
+       tdev->poll_dev = poll_dev;
+       tdev->dev = dev;
+       tdev->pdata = pdata;
+
+       error = input_register_polled_device(poll_dev);
+       if (error) {
+               dev_err(dev, "unable to register polled device,

err=%d\n", + error);

drivers/input/misc/gpio_tilt_polled.c new file +18 -0
+               goto err_free_polldev;
+       }
+
+       platform_set_drvdata(pdev, tdev);
+
+       return 0;
+
+err_free_polldev:
+       input_free_polled_device(poll_dev);
+err_free_gpios:
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+err_free_tdev:
+       kfree(tdev);
+
+       return error;
+}
+
+static int __devexit gpio_tilt_polled_remove(struct platform_device

*pdev) +{

drivers/input/misc/gpio_tilt_polled.c new file +30 -0
+       struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_polled_device(tdev->poll_dev);
+       input_free_polled_device(tdev->poll_dev);
+
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+
+       kfree(tdev);
+
+       return 0;
+}
+
+static struct platform_driver gpio_tilt_polled_driver = {
+       .probe  = gpio_tilt_polled_probe,
+       .remove = __devexit_p(gpio_tilt_polled_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(gpio_tilt_polled_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <[email protected]>");
+MODULE_DESCRIPTION("Polled GPIO tilt driver");
+MODULE_ALIAS("platform:" DRV_NAME);
include/linux/gpio_tilt.h new file +23 -0
new file mode 100644
index 0000000..809fe93
@@ -0,0 +1,73 @@
+#ifndef _GPIO_TILT_H
+#define _GPIO_TILT_H
+
+/**
+ * struct gpio_tilt_axis - Axis used by the tilt switch
+ * @axis:              Constant describing the axis, e.g. ABS_X
+ * @min:               minimum value for abs_param
+ * @max:               maximum value for abs_param
+ * @fuzz:              fuzz value for abs_param
+ * @flat:              flat value for abs_param
+ */
+struct gpio_tilt_axis {
+       int axis;
+       int min;
+       int max;
+       int fuzz;
+       int flat;
+};
+
+/**
+ * struct gpio_tilt_state - state description
+ * @gpios:             bitfield of gpio target-states for the value
+ * @axes:              array containing the axes settings for the gpio

state + * The array indizes must correspond to the
axes defined + * in platform_data
+ *
+ * This structure describes a supported axis settings
+ * and the necessary gpio-state which represent it.
+ *
+ * The n-th bit in the bitfield describes the state of the n-th GPIO
+ * from the gpios-array defined in gpio_regulator_config below.
+ */

include/linux/gpio_tilt.h new file +8 -0
+struct gpio_tilt_state {
+       int gpios;
+       int *axes;
+};
+
+/**
+ * struct gpio_tilt_platform_data
+ * @gpios:             Array containing the gpios determining the tilt

state + * @nr_gpios: Number of gpios

+ * @axes:              Array of gpio_tilt_axis descriptions
+ * @nr_axes:           Number of axes
+ * @states:            Array of gpio_tilt_state entries describing
+ *                     the gpio state for specific tilts
+ * @nr_states:         Number of states available

+ * @debounce_interval: debounce ticks interval in msecs
+ * @poll_interval: polling interval in msecs - for polling driver
only + * @enable: callback to enable the tilt switch
+ * @disable: callback to disable the tilt switch
+ *
+ * This structure contains gpio-tilt-switch configuration
+ * information that must be passed by platform code to the
+ * gpio-tilt input driver.
+ */

include/linux/gpio_tilt.h new file +18 -1
+struct gpio_tilt_platform_data {
+       struct gpio *gpios;
+       int nr_gpios;
+
+       struct gpio_tilt_axis *axes;
+       int nr_axes;
+
+       struct gpio_tilt_state *states;
+       int nr_states;
+
+       int debounce_interval;
+
+       unsigned int poll_interval;
+       int (*enable)(struct device *dev);
+       void (*disable)(struct device *dev);
+};
+
+#endif
--

1.7.5.4

Quoted 9 lines
Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw
Quoted 240 lines · Heiko Stübner

Hi Shubhrajyoti,

Am Dienstag, 29. November 2011, 15:59:29 schrieb Shubhrajyoti Datta:

Quoted 229 lines

Hi Heiko,

Quoted 226 lines · Heiko Stübner

There exist tilt switches that simply report their tilt-state via some gpios.

The number and orientation of their axes can vary depending on the switch used and the build of the device. Also two or more one-axis switches could be combined to provide multi-dimensional orientation.

One example of a device using such a switch is the family of Qisda ebook readers, where the switch provides information about the landscape / portrait orientation of the device. The example in Documentation/input/gpio-tilt.txt documents exactly this one-axis device.

---
changes since v2: use module_platform_driver changes since v1: address comments from Dmitry Torokhov
* bdev -> tdev
* report initial axis state during open and not during probe
* don't clone platform data and use the original instead

 Documentation/input/gpio-tilt.txt     |  103 ++++++++++++++++ drivers/input/misc/Kconfig            |   14 ++ drivers/input/misc/Makefile           |    1 + drivers/input/misc/gpio_tilt_polled.c |  214 +++++++++++++++++++++++++++++++++ include/linux/gpio_tilt.h |   73 +++++++++++

 5 files changed, 405 insertions(+), 0 deletions(-)

 create mode 100644 Documentation/input/gpio-tilt.txt create mode 100644 drivers/input/misc/gpio_tilt_polled.c create mode 100644 include/linux/gpio_tilt.h

(quoted diff) +0 -0

b/Documentation/input/gpio-tilt.txt new file mode 100644 index 0000000..06d60c3

Documentation/input/gpio-tilt.txt new file +20 -0
@@ -0,0 +1,103 @@
+Driver for tilt-switches connected via GPIOs
+============================================
+
+Generic driver to read data from tilt switches connected via gpios.
+Orientation can be provided by one or more than one tilt switches,
+i.e. each tilt switch providing one axis, and the number of axes
+is also not limited.
+
+
+Data structures:
+----------------
+
+The array of struct gpio in the gpios field is used to list the gpios
+that represent the current tilt state.
+
+The array of struct gpio_tilt_axis describes the axes that are reported
+to the input system. The values set therein are used for the
+input_set_abs_params calls needed to init the axes.
+
+The array of struct gpio_tilt_state maps gpio states to the

corresponding +values to report. The gpio state is represented as a bitfield where the +bit-index corresponds to the index of the gpio in the struct gpio array. +In the same manner the values stored in the axes array correspond to +the elements of the gpio_tilt_axis-array.

Documentation/input/gpio-tilt.txt new file +6 -0
+
+
+Example:
+--------
+
+Example configuration for a single TS1003 tilt switch that rotates

around +one axis in 4 steps and emitts the current tilt via two GPIOs.

Documentation/input/gpio-tilt.txt new file +72 -0
+
+static int sg060_tilt_enable(struct device *dev) {
+       /* code to enable the sensors */
+};
+
+static void sg060_tilt_disable(struct device *dev) {
+       /* code to disable the sensors */
+};
+
+static struct gpio sg060_tilt_gpios[] = {
+       { SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" },
+       { SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" },
+};
+
+static struct gpio_tilt_state sg060_tilt_states[] = {
+       {
+               .gpios = (0 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       0,
+               },
+       }, {
+               .gpios = (0 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       1, /* 90 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (1 << 0),
+               .axes = (int[]) {
+                       2, /* 180 degrees */
+               },
+       }, {
+               .gpios = (1 << 1) | (0 << 0),
+               .axes = (int[]) {
+                       3, /* 270 degrees */
+               },
+       },
+};
+
+static struct gpio_tilt_axis sg060_tilt_axes[] = {
+       {
+               .axis = ABS_RY,
+               .min = 0,
+               .max = 3,
+               .fuzz = 0,
+               .flat = 0,
+       },
+};
+
+static struct gpio_tilt_platform_data sg060_tilt_pdata= {
+       .gpios = sg060_tilt_gpios,
+       .nr_gpios = ARRAY_SIZE(sg060_tilt_gpios),
+
+       .axes = sg060_tilt_axes,
+       .nr_axes = ARRAY_SIZE(sg060_tilt_axes),
+
+       .states = sg060_tilt_states,
+       .nr_states = ARRAY_SIZE(sg060_tilt_states),
+
+       .debounce_interval = 100,
+
+       .poll_interval = 1000,
+       .enable = sg060_tilt_enable,
+       .disable = sg060_tilt_disable,
+};
+
+static struct platform_device sg060_device_tilt = {
+       .name = "gpio-tilt-polled",
+       .id = -1,
+       .dev = {
+               .platform_data = &sg060_tilt_pdata,
+       },
+};
drivers/input/misc/Kconfig +0 -0
index 22d875f..e53b443 100644
@@ -179,6 +179,20 @@ config INPUT_APANEL

        To compile this driver as a module, choose M here: the module will be called apanel.

drivers/input/misc/Kconfig +14 -0
+config INPUT_GPIO_TILT_POLLED
+       tristate "Polled GPIO tilt switch"
+       depends on GENERIC_GPIO
+       select INPUT_POLLDEV
+       help
+         This driver implements support for tilt switches connected
+         to GPIO pins that are not capable of generating interrupts.
+
+         The list of gpios to use and the mapping of their states
+         to specific angles is done via platform data.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gpio_tilt_polled.
+

 config INPUT_IXP4XX_BEEPER
       tristate "IXP4XX Beeper support"
       depends on ARCH_IXP4XX

drivers/input/misc/Makefile +0 -0
index a244fc6..90070c1 100644
@@ -23,6 +23,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C)               +=

cma3000_d0x_i2c.o obj-$(CONFIG_INPUT_COBALT_BTNS)                += cobalt_btns.o obj-$(CONFIG_INPUT_DM355EVM)           += dm355evm_keys.o obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o +obj-$(CONFIG_INPUT_GPIO_TILT_POLLED)   += gpio_tilt_polled.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE)     += keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9)              += kxtj9.o

(quoted diff) +0 -0

b/drivers/input/misc/gpio_tilt_polled.c new file mode 100644 index 0000000..ebc3f08

drivers/input/misc/gpio_tilt_polled.c new file +43 -0
@@ -0,0 +1,214 @@
+/*
+ *  Driver for tilt switches connected via GPIO lines
+ *  not capable of generating interrupts
+ *
+ *  Copyright (C) 2011 Heiko Stuebner <[email protected]>
+ *
+ *  based on: /drivers/input/keyboard/gpio_keys_polled.c
+ *
+ *  Copyright (C) 2007-2010 Gabor Juhos <[email protected]>
+ *  Copyright (C) 2010 Nuno Goncalves <[email protected]>
+ *
+ *  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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_tilt.h>
+
+#define DRV_NAME       "gpio-tilt-polled"
+
+struct gpio_tilt_polled_dev {
+       struct input_polled_dev *poll_dev;
+       struct device *dev;
+       struct gpio_tilt_platform_data *pdata;
+
+       int last_state;
+
+       int threshold;
+       int count;
+};
+
+static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
Quoted 8 lines

drivers/input/misc/gpio_tilt_polled.c line 49

Quoted 6 lines
drivers/input/misc/gpio_tilt_polled.c new file +6 -0
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+       struct input_dev *input = dev->input;
+       struct gpio_tilt_state *tilt_state = NULL;
+       int state, i;
+
+       if (tdev->count < tdev->threshold) {

Nitpick : the braces are not necessary.

Quoted 4 lines

hmm ... for me it's easier to read if the style of the braces does not change between if and else, i.e. both with or without braces.
And the kernel CodingStyle-file seems also to be in my favor ;-) [starting from line 169].

I see thanks for correcting.

Quoted 64 lines
Quoted 56 lines
Quoted 56 lines
drivers/input/misc/gpio_tilt_polled.c new file +5 -0
+               tdev->count++;
+       } else {
+               state = 0;
+               for (i = 0; i < pdata->nr_gpios; i++)
+                       state |= (!!gpio_get_value(pdata->gpios[i].gpio)

<< i); +
+               if (state != tdev->last_state) {
+                       for (i = 0; i < pdata->nr_states; i++)
+                               if (pdata->states[i].gpios == state)
+                                       tilt_state = &pdata->states[i];

drivers/input/misc/gpio_tilt_polled.c new file +5 -0
+
+                       if (tilt_state) {
+                               for (i = 0; i < pdata->nr_axes; i++)
+                                       input_report_abs(input,
+

 pdata->axes[i].axis, + tilt_state->axes[i]); +
+                               input_sync(input);
+                       }

drivers/input/misc/gpio_tilt_polled.c new file +31 -0
+
+                       tdev->count = 0;
+                       tdev->last_state = state;
+               }
+       }
+}
+
+static void gpio_tilt_polled_open(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->enable)
+               pdata->enable(tdev->dev);
+
+       /* report initial state of the axes */
+       tdev->last_state = -1;
+       tdev->count = tdev->threshold;
+       gpio_tilt_polled_poll(tdev->poll_dev);
+}
+
+static void gpio_tilt_polled_close(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+
+       if (pdata->disable)
+               pdata->disable(tdev->dev);
+}
+
+static int __devinit gpio_tilt_polled_probe(struct platform_device

*pdev) +{
+       struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct gpio_tilt_polled_dev *tdev;
+       struct input_polled_dev *poll_dev;

Quoted 8 lines
Quoted 5 lines

+       struct input_dev *input;
+       int error, i;
+
+       if (!pdata || !pdata->poll_interval)
+               return -EINVAL;

Could we have a default poll interval if passed 0 ? Feel free to ignore if you feel otherwise.

Quoted 3 lines

For me either way is fine but I'm not sure what would be a generic enough default value for most cases (500, 1000 ? ).

I was thinking that just because someone doesn't populate the timeout gets penalised max ie failure of probe.

1000 looks good to me also your documentation suggests so . However I leave the decision to you.

Quoted 187 lines
Quoted 187 lines
Quoted 187 lines
drivers/input/misc/gpio_tilt_polled.c new file +42 -0
+
+       tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL);
+       if (!tdev) {
+               dev_err(dev, "no memory for private data\n");
+               return -ENOMEM;
+       }
+
+       error = gpio_request_array(pdata->gpios, pdata->nr_gpios);
+       if (error) {
+               dev_err(dev,
+                  "Could not request tilt GPIOs: %d\n", error);
+               goto err_free_tdev;
+       }
+
+       poll_dev = input_allocate_polled_device();
+       if (!poll_dev) {
+               dev_err(dev, "no memory for polled device\n");
+               error = -ENOMEM;
+               goto err_free_gpios;
+       }
+
+       poll_dev->private = tdev;
+       poll_dev->poll = gpio_tilt_polled_poll;
+       poll_dev->poll_interval = pdata->poll_interval;
+       poll_dev->open = gpio_tilt_polled_open;
+       poll_dev->close = gpio_tilt_polled_close;
+
+       input = poll_dev->input;
+
+       input->name = pdev->name;
+       input->phys = DRV_NAME"/input0";
+       input->dev.parent = &pdev->dev;
+
+       input->id.bustype = BUS_HOST;
+       input->id.vendor = 0x0001;
+       input->id.product = 0x0001;
+       input->id.version = 0x0100;
+
+       __set_bit(EV_ABS, input->evbit);
+       for (i = 0; i < pdata->nr_axes; i++) {
+               input_set_abs_params(input, pdata->axes[i].axis,
+                                    pdata->axes[i].min,

pdata->axes[i].max, +
 pdata->axes[i].fuzz, pdata->axes[i].flat); +       }

drivers/input/misc/gpio_tilt_polled.c new file +11 -0
+
+       tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval,
+                                      pdata->poll_interval);
+
+       tdev->poll_dev = poll_dev;
+       tdev->dev = dev;
+       tdev->pdata = pdata;
+
+       error = input_register_polled_device(poll_dev);
+       if (error) {
+               dev_err(dev, "unable to register polled device,

err=%d\n", +                       error);
+               goto err_free_polldev;
+       }

drivers/input/misc/gpio_tilt_polled.c new file +16 -0
+
+       platform_set_drvdata(pdev, tdev);
+
+       return 0;
+
+err_free_polldev:
+       input_free_polled_device(poll_dev);
+err_free_gpios:
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+err_free_tdev:
+       kfree(tdev);
+
+       return error;
+}
+
+static int __devexit gpio_tilt_polled_remove(struct platform_device

*pdev) +{
+       struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;

drivers/input/misc/gpio_tilt_polled.c new file +28 -0
+
+       platform_set_drvdata(pdev, NULL);
+
+       input_unregister_polled_device(tdev->poll_dev);
+       input_free_polled_device(tdev->poll_dev);
+
+       gpio_free_array(pdata->gpios, pdata->nr_gpios);
+
+       kfree(tdev);
+
+       return 0;
+}
+
+static struct platform_driver gpio_tilt_polled_driver = {
+       .probe  = gpio_tilt_polled_probe,
+       .remove = __devexit_p(gpio_tilt_polled_remove),
+       .driver = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+module_platform_driver(gpio_tilt_polled_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Heiko Stuebner <[email protected]>");
+MODULE_DESCRIPTION("Polled GPIO tilt driver");
+MODULE_ALIAS("platform:" DRV_NAME);
include/linux/gpio_tilt.h new file +23 -0
new file mode 100644
index 0000000..809fe93
@@ -0,0 +1,73 @@
+#ifndef _GPIO_TILT_H
+#define _GPIO_TILT_H
+
+/**
+ * struct gpio_tilt_axis - Axis used by the tilt switch
+ * @axis:              Constant describing the axis, e.g. ABS_X
+ * @min:               minimum value for abs_param
+ * @max:               maximum value for abs_param
+ * @fuzz:              fuzz value for abs_param
+ * @flat:              flat value for abs_param
+ */
+struct gpio_tilt_axis {
+       int axis;
+       int min;
+       int max;
+       int fuzz;
+       int flat;
+};
+
+/**
+ * struct gpio_tilt_state - state description
+ * @gpios:             bitfield of gpio target-states for the value
+ * @axes:              array containing the axes settings for the gpio

state + *                     The array indizes must correspond to the axes defined + *                     in platform_data
+ *
+ * This structure describes a supported axis settings
+ * and the necessary gpio-state which represent it.
+ *
+ * The n-th bit in the bitfield describes the state of the n-th GPIO
+ * from the gpios-array defined in gpio_regulator_config below.
+ */

include/linux/gpio_tilt.h new file +8 -0
+struct gpio_tilt_state {
+       int gpios;
+       int *axes;
+};
+
+/**
+ * struct gpio_tilt_platform_data
+ * @gpios:             Array containing the gpios determining the tilt

state + * @nr_gpios:          Number of gpios
+ * @axes:              Array of gpio_tilt_axis descriptions
+ * @nr_axes:           Number of axes
+ * @states:            Array of gpio_tilt_state entries describing
+ *                     the gpio state for specific tilts
+ * @nr_states:         Number of states available
+ * @debounce_interval: debounce ticks interval in msecs
+ * @poll_interval:     polling interval in msecs - for polling driver only + * @enable:            callback to enable the tilt switch
+ * @disable:           callback to disable the tilt switch
+ *
+ * This structure contains gpio-tilt-switch configuration
+ * information that must be passed by platform code to the
+ * gpio-tilt input driver.
+ */

include/linux/gpio_tilt.h new file +18 -1
+struct gpio_tilt_platform_data {
+       struct gpio *gpios;
+       int nr_gpios;
+
+       struct gpio_tilt_axis *axes;
+       int nr_axes;
+
+       struct gpio_tilt_state *states;
+       int nr_states;
+
+       int debounce_interval;
+
+       unsigned int poll_interval;
+       int (*enable)(struct device *dev);
+       void (*disable)(struct device *dev);
+};
+
+#endif
--

1.7.5.4

Quoted 10 lines
Quoted 9 lines
Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

maintainer
#4 lore raw
In reply to Heiko Stübner
Quoted 17 lines · Heiko Stübner

Hi Shubhrajyoti,

Am Dienstag, 29. November 2011, 15:59:29 schrieb Shubhrajyoti Datta:

Quoted 14 lines

Hi Heiko,

drivers/input/misc/gpio_tilt_polled.c line 49

Quoted 9 lines · Heiko Stübner
drivers/input/misc/gpio_tilt_polled.c new file +9 -0
+static void gpio_tilt_polled_poll(struct input_polled_dev *dev)
+{
+       struct gpio_tilt_polled_dev *tdev = dev->private;
+       struct gpio_tilt_platform_data *pdata = tdev->pdata;
+       struct input_dev *input = dev->input;
+       struct gpio_tilt_state *tilt_state = NULL;
+       int state, i;
+
+       if (tdev->count < tdev->threshold) {

Nitpick : the braces are not necessary.

Quoted 4 lines

hmm ... for me it's easier to read if the style of the braces does not change between if and else, i.e. both with or without braces.
And the kernel CodingStyle-file seems also to be in my favor ;-) [starting from line 169].

Yep, when one branch requires braces it is preferred to have then on all branches.

Quoted 14 lines
Quoted 6 lines
Quoted 6 lines

+static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev) +{

drivers/input/misc/gpio_tilt_polled.c new file +4 -0
+       struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct gpio_tilt_polled_dev *tdev;
+       struct input_polled_dev *poll_dev;
Quoted 8 lines

drivers/input/misc/gpio_tilt_polled.c line 109

Quoted 5 lines
drivers/input/misc/gpio_tilt_polled.c new file +5 -0
+       struct input_dev *input;
+       int error, i;
+
+       if (!pdata || !pdata->poll_interval)
+               return -EINVAL;

Could we have a default poll interval if passed 0 ? Feel free to ignore if you feel otherwise.

Quoted 3 lines

For me either way is fine but I'm not sure what would be a generic enough default value for most cases (500, 1000 ? ).

I'd rather error out then give default which we can't sanely select. Then platform integrator will be alerted early and select appropriate value.

Thanks.

Signature · 5 lines
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
maintainer
#5 lore raw
In reply to Heiko Stübner
Quoted 6 lines · Heiko Stübner

There exist tilt switches that simply report their tilt-state via some gpios.

The number and orientation of their axes can vary depending on the switch used and the build of the device. Also two or more one-axis switches could be combined to provide multi-dimensional orientation.

Quoted 8 lines

One example of a device using such a switch is the family of Qisda ebook readers, where the switch provides information about the landscape / portrait orientation of the device. The example in Documentation/input/gpio-tilt.txt documents exactly this one-axis device.

---
changes since v2: use module_platform_driver

Could you please separate this change? I applied previous version to my tree and I am not sure when module_driver changes will hit mainline...

Thanks.

Signature · 5 lines
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#6 lore raw
Quoted 2 lines · Dmitry Torokhov

Could you please separate this change? I applied previous version to my tree and I am not sure when module_driver changes will hit mainline...

module_platform_driver is in Linus' tree already.

maintainer
#7 lore raw
Quoted 6 lines · Mark Brown
Quoted 2 lines · Dmitry Torokhov

Could you please separate this change? I applied previous version to my tree and I am not sure when module_driver changes will hit mainline...

module_platform_driver is in Linus' tree already.

Ah, indeed, its the rest of the buses that are missing. Anyway, could I still get a separate patch, please?

Signature · 1 line
Dmitry
maintainer
#8 lore raw
Quoted 11 lines · Dmitry Torokhov
Quoted 6 lines · Mark Brown
Quoted 2 lines · Dmitry Torokhov

Could you please separate this change? I applied previous version to my tree and I am not sure when module_driver changes will hit mainline...

module_platform_driver is in Linus' tree already.

Ah, indeed, its the rest of the buses that are missing. Anyway, could I still get a separate patch, please?

Ah, never mind, I haven't pushed it out yet so I'll take the latest version.

Signature · 1 line
Dmitry
#9 lore raw

Am Dienstag 29 November 2011, 20:06:02 schrieb Dmitry Torokhov:

Quoted 7 lines · Dmitry Torokhov
Quoted 6 lines · Mark Brown
Quoted 5 lines · Dmitry Torokhov
Quoted 3 lines

Could you please separate this change? I applied previous version to my tree and I am not sure when module_driver changes will hit mainline...

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

module_platform_driver is in Linus' tree already.

Ah, indeed, its the rest of the buses that are missing. Anyway, could I still get a separate patch, please?

Ah, never mind, I haven't pushed it out yet so I'll take the latest version.

very cool :-)

Thanks
Heiko