Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: 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.

Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Heiko Stübner and committed by
Dmitry Torokhov
3bfd5c5b a6c61789

+404
+103
Documentation/input/gpio-tilt.txt
··· 1 + Driver for tilt-switches connected via GPIOs 2 + ============================================ 3 + 4 + Generic driver to read data from tilt switches connected via gpios. 5 + Orientation can be provided by one or more than one tilt switches, 6 + i.e. each tilt switch providing one axis, and the number of axes 7 + is also not limited. 8 + 9 + 10 + Data structures: 11 + ---------------- 12 + 13 + The array of struct gpio in the gpios field is used to list the gpios 14 + that represent the current tilt state. 15 + 16 + The array of struct gpio_tilt_axis describes the axes that are reported 17 + to the input system. The values set therein are used for the 18 + input_set_abs_params calls needed to init the axes. 19 + 20 + The array of struct gpio_tilt_state maps gpio states to the corresponding 21 + values to report. The gpio state is represented as a bitfield where the 22 + bit-index corresponds to the index of the gpio in the struct gpio array. 23 + In the same manner the values stored in the axes array correspond to 24 + the elements of the gpio_tilt_axis-array. 25 + 26 + 27 + Example: 28 + -------- 29 + 30 + Example configuration for a single TS1003 tilt switch that rotates around 31 + one axis in 4 steps and emitts the current tilt via two GPIOs. 32 + 33 + static int sg060_tilt_enable(struct device *dev) { 34 + /* code to enable the sensors */ 35 + }; 36 + 37 + static void sg060_tilt_disable(struct device *dev) { 38 + /* code to disable the sensors */ 39 + }; 40 + 41 + static struct gpio sg060_tilt_gpios[] = { 42 + { SG060_TILT_GPIO_SENSOR1, GPIOF_IN, "tilt_sensor1" }, 43 + { SG060_TILT_GPIO_SENSOR2, GPIOF_IN, "tilt_sensor2" }, 44 + }; 45 + 46 + static struct gpio_tilt_state sg060_tilt_states[] = { 47 + { 48 + .gpios = (0 << 1) | (0 << 0), 49 + .axes = (int[]) { 50 + 0, 51 + }, 52 + }, { 53 + .gpios = (0 << 1) | (1 << 0), 54 + .axes = (int[]) { 55 + 1, /* 90 degrees */ 56 + }, 57 + }, { 58 + .gpios = (1 << 1) | (1 << 0), 59 + .axes = (int[]) { 60 + 2, /* 180 degrees */ 61 + }, 62 + }, { 63 + .gpios = (1 << 1) | (0 << 0), 64 + .axes = (int[]) { 65 + 3, /* 270 degrees */ 66 + }, 67 + }, 68 + }; 69 + 70 + static struct gpio_tilt_axis sg060_tilt_axes[] = { 71 + { 72 + .axis = ABS_RY, 73 + .min = 0, 74 + .max = 3, 75 + .fuzz = 0, 76 + .flat = 0, 77 + }, 78 + }; 79 + 80 + static struct gpio_tilt_platform_data sg060_tilt_pdata= { 81 + .gpios = sg060_tilt_gpios, 82 + .nr_gpios = ARRAY_SIZE(sg060_tilt_gpios), 83 + 84 + .axes = sg060_tilt_axes, 85 + .nr_axes = ARRAY_SIZE(sg060_tilt_axes), 86 + 87 + .states = sg060_tilt_states, 88 + .nr_states = ARRAY_SIZE(sg060_tilt_states), 89 + 90 + .debounce_interval = 100, 91 + 92 + .poll_interval = 1000, 93 + .enable = sg060_tilt_enable, 94 + .disable = sg060_tilt_disable, 95 + }; 96 + 97 + static struct platform_device sg060_device_tilt = { 98 + .name = "gpio-tilt-polled", 99 + .id = -1, 100 + .dev = { 101 + .platform_data = &sg060_tilt_pdata, 102 + }, 103 + };
+14
drivers/input/misc/Kconfig
··· 179 179 To compile this driver as a module, choose M here: the module will 180 180 be called apanel. 181 181 182 + config INPUT_GPIO_TILT_POLLED 183 + tristate "Polled GPIO tilt switch" 184 + depends on GENERIC_GPIO 185 + select INPUT_POLLDEV 186 + help 187 + This driver implements support for tilt switches connected 188 + to GPIO pins that are not capable of generating interrupts. 189 + 190 + The list of gpios to use and the mapping of their states 191 + to specific angles is done via platform data. 192 + 193 + To compile this driver as a module, choose M here: the 194 + module will be called gpio_tilt_polled. 195 + 182 196 config INPUT_IXP4XX_BEEPER 183 197 tristate "IXP4XX Beeper support" 184 198 depends on ARCH_IXP4XX
+1
drivers/input/misc/Makefile
··· 23 23 obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o 24 24 obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o 25 25 obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o 26 + obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o 26 27 obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o 27 28 obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o 28 29 obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
+213
drivers/input/misc/gpio_tilt_polled.c
··· 1 + /* 2 + * Driver for tilt switches connected via GPIO lines 3 + * not capable of generating interrupts 4 + * 5 + * Copyright (C) 2011 Heiko Stuebner <heiko@sntech.de> 6 + * 7 + * based on: drivers/input/keyboard/gpio_keys_polled.c 8 + * 9 + * Copyright (C) 2007-2010 Gabor Juhos <juhosg@openwrt.org> 10 + * Copyright (C) 2010 Nuno Goncalves <nunojpg@gmail.com> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + */ 16 + 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/init.h> 20 + #include <linux/slab.h> 21 + #include <linux/input.h> 22 + #include <linux/input-polldev.h> 23 + #include <linux/ioport.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/gpio.h> 26 + #include <linux/input/gpio_tilt.h> 27 + 28 + #define DRV_NAME "gpio-tilt-polled" 29 + 30 + struct gpio_tilt_polled_dev { 31 + struct input_polled_dev *poll_dev; 32 + struct device *dev; 33 + const struct gpio_tilt_platform_data *pdata; 34 + 35 + int last_state; 36 + 37 + int threshold; 38 + int count; 39 + }; 40 + 41 + static void gpio_tilt_polled_poll(struct input_polled_dev *dev) 42 + { 43 + struct gpio_tilt_polled_dev *tdev = dev->private; 44 + const struct gpio_tilt_platform_data *pdata = tdev->pdata; 45 + struct input_dev *input = dev->input; 46 + struct gpio_tilt_state *tilt_state = NULL; 47 + int state, i; 48 + 49 + if (tdev->count < tdev->threshold) { 50 + tdev->count++; 51 + } else { 52 + state = 0; 53 + for (i = 0; i < pdata->nr_gpios; i++) 54 + state |= (!!gpio_get_value(pdata->gpios[i].gpio) << i); 55 + 56 + if (state != tdev->last_state) { 57 + for (i = 0; i < pdata->nr_states; i++) 58 + if (pdata->states[i].gpios == state) 59 + tilt_state = &pdata->states[i]; 60 + 61 + if (tilt_state) { 62 + for (i = 0; i < pdata->nr_axes; i++) 63 + input_report_abs(input, 64 + pdata->axes[i].axis, 65 + tilt_state->axes[i]); 66 + 67 + input_sync(input); 68 + } 69 + 70 + tdev->count = 0; 71 + tdev->last_state = state; 72 + } 73 + } 74 + } 75 + 76 + static void gpio_tilt_polled_open(struct input_polled_dev *dev) 77 + { 78 + struct gpio_tilt_polled_dev *tdev = dev->private; 79 + const struct gpio_tilt_platform_data *pdata = tdev->pdata; 80 + 81 + if (pdata->enable) 82 + pdata->enable(tdev->dev); 83 + 84 + /* report initial state of the axes */ 85 + tdev->last_state = -1; 86 + tdev->count = tdev->threshold; 87 + gpio_tilt_polled_poll(tdev->poll_dev); 88 + } 89 + 90 + static void gpio_tilt_polled_close(struct input_polled_dev *dev) 91 + { 92 + struct gpio_tilt_polled_dev *tdev = dev->private; 93 + const struct gpio_tilt_platform_data *pdata = tdev->pdata; 94 + 95 + if (pdata->disable) 96 + pdata->disable(tdev->dev); 97 + } 98 + 99 + static int __devinit gpio_tilt_polled_probe(struct platform_device *pdev) 100 + { 101 + const struct gpio_tilt_platform_data *pdata = pdev->dev.platform_data; 102 + struct device *dev = &pdev->dev; 103 + struct gpio_tilt_polled_dev *tdev; 104 + struct input_polled_dev *poll_dev; 105 + struct input_dev *input; 106 + int error, i; 107 + 108 + if (!pdata || !pdata->poll_interval) 109 + return -EINVAL; 110 + 111 + tdev = kzalloc(sizeof(struct gpio_tilt_polled_dev), GFP_KERNEL); 112 + if (!tdev) { 113 + dev_err(dev, "no memory for private data\n"); 114 + return -ENOMEM; 115 + } 116 + 117 + error = gpio_request_array(pdata->gpios, pdata->nr_gpios); 118 + if (error) { 119 + dev_err(dev, 120 + "Could not request tilt GPIOs: %d\n", error); 121 + goto err_free_tdev; 122 + } 123 + 124 + poll_dev = input_allocate_polled_device(); 125 + if (!poll_dev) { 126 + dev_err(dev, "no memory for polled device\n"); 127 + error = -ENOMEM; 128 + goto err_free_gpios; 129 + } 130 + 131 + poll_dev->private = tdev; 132 + poll_dev->poll = gpio_tilt_polled_poll; 133 + poll_dev->poll_interval = pdata->poll_interval; 134 + poll_dev->open = gpio_tilt_polled_open; 135 + poll_dev->close = gpio_tilt_polled_close; 136 + 137 + input = poll_dev->input; 138 + 139 + input->name = pdev->name; 140 + input->phys = DRV_NAME"/input0"; 141 + input->dev.parent = &pdev->dev; 142 + 143 + input->id.bustype = BUS_HOST; 144 + input->id.vendor = 0x0001; 145 + input->id.product = 0x0001; 146 + input->id.version = 0x0100; 147 + 148 + __set_bit(EV_ABS, input->evbit); 149 + for (i = 0; i < pdata->nr_axes; i++) 150 + input_set_abs_params(input, pdata->axes[i].axis, 151 + pdata->axes[i].min, pdata->axes[i].max, 152 + pdata->axes[i].fuzz, pdata->axes[i].flat); 153 + 154 + tdev->threshold = DIV_ROUND_UP(pdata->debounce_interval, 155 + pdata->poll_interval); 156 + 157 + tdev->poll_dev = poll_dev; 158 + tdev->dev = dev; 159 + tdev->pdata = pdata; 160 + 161 + error = input_register_polled_device(poll_dev); 162 + if (error) { 163 + dev_err(dev, "unable to register polled device, err=%d\n", 164 + error); 165 + goto err_free_polldev; 166 + } 167 + 168 + platform_set_drvdata(pdev, tdev); 169 + 170 + return 0; 171 + 172 + err_free_polldev: 173 + input_free_polled_device(poll_dev); 174 + err_free_gpios: 175 + gpio_free_array(pdata->gpios, pdata->nr_gpios); 176 + err_free_tdev: 177 + kfree(tdev); 178 + 179 + return error; 180 + } 181 + 182 + static int __devexit gpio_tilt_polled_remove(struct platform_device *pdev) 183 + { 184 + struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev); 185 + const struct gpio_tilt_platform_data *pdata = tdev->pdata; 186 + 187 + platform_set_drvdata(pdev, NULL); 188 + 189 + input_unregister_polled_device(tdev->poll_dev); 190 + input_free_polled_device(tdev->poll_dev); 191 + 192 + gpio_free_array(pdata->gpios, pdata->nr_gpios); 193 + 194 + kfree(tdev); 195 + 196 + return 0; 197 + } 198 + 199 + static struct platform_driver gpio_tilt_polled_driver = { 200 + .probe = gpio_tilt_polled_probe, 201 + .remove = __devexit_p(gpio_tilt_polled_remove), 202 + .driver = { 203 + .name = DRV_NAME, 204 + .owner = THIS_MODULE, 205 + }, 206 + }; 207 + 208 + module_platform_driver(gpio_tilt_polled_driver); 209 + 210 + MODULE_LICENSE("GPL v2"); 211 + MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); 212 + MODULE_DESCRIPTION("Polled GPIO tilt driver"); 213 + MODULE_ALIAS("platform:" DRV_NAME);
+73
include/linux/input/gpio_tilt.h
··· 1 + #ifndef _INPUT_GPIO_TILT_H 2 + #define _INPUT_GPIO_TILT_H 3 + 4 + /** 5 + * struct gpio_tilt_axis - Axis used by the tilt switch 6 + * @axis: Constant describing the axis, e.g. ABS_X 7 + * @min: minimum value for abs_param 8 + * @max: maximum value for abs_param 9 + * @fuzz: fuzz value for abs_param 10 + * @flat: flat value for abs_param 11 + */ 12 + struct gpio_tilt_axis { 13 + int axis; 14 + int min; 15 + int max; 16 + int fuzz; 17 + int flat; 18 + }; 19 + 20 + /** 21 + * struct gpio_tilt_state - state description 22 + * @gpios: bitfield of gpio target-states for the value 23 + * @axes: array containing the axes settings for the gpio state 24 + * The array indizes must correspond to the axes defined 25 + * in platform_data 26 + * 27 + * This structure describes a supported axis settings 28 + * and the necessary gpio-state which represent it. 29 + * 30 + * The n-th bit in the bitfield describes the state of the n-th GPIO 31 + * from the gpios-array defined in gpio_regulator_config below. 32 + */ 33 + struct gpio_tilt_state { 34 + int gpios; 35 + int *axes; 36 + }; 37 + 38 + /** 39 + * struct gpio_tilt_platform_data 40 + * @gpios: Array containing the gpios determining the tilt state 41 + * @nr_gpios: Number of gpios 42 + * @axes: Array of gpio_tilt_axis descriptions 43 + * @nr_axes: Number of axes 44 + * @states: Array of gpio_tilt_state entries describing 45 + * the gpio state for specific tilts 46 + * @nr_states: Number of states available 47 + * @debounce_interval: debounce ticks interval in msecs 48 + * @poll_interval: polling interval in msecs - for polling driver only 49 + * @enable: callback to enable the tilt switch 50 + * @disable: callback to disable the tilt switch 51 + * 52 + * This structure contains gpio-tilt-switch configuration 53 + * information that must be passed by platform code to the 54 + * gpio-tilt input driver. 55 + */ 56 + struct gpio_tilt_platform_data { 57 + struct gpio *gpios; 58 + int nr_gpios; 59 + 60 + struct gpio_tilt_axis *axes; 61 + int nr_axes; 62 + 63 + struct gpio_tilt_state *states; 64 + int nr_states; 65 + 66 + int debounce_interval; 67 + 68 + unsigned int poll_interval; 69 + int (*enable)(struct device *dev); 70 + void (*disable)(struct device *dev); 71 + }; 72 + 73 + #endif