diff options
Diffstat (limited to 'drivers/input/misc/gpio_output.c')
-rw-r--r-- | drivers/input/misc/gpio_output.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/input/misc/gpio_output.c b/drivers/input/misc/gpio_output.c new file mode 100644 index 00000000000..2aac2fad0a1 --- /dev/null +++ b/drivers/input/misc/gpio_output.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* drivers/input/misc/gpio_output.c | ||
2 | * | ||
3 | * Copyright (C) 2007 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/gpio_event.h> | ||
19 | |||
20 | int gpio_event_output_event( | ||
21 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
22 | void **data, unsigned int dev, unsigned int type, | ||
23 | unsigned int code, int value) | ||
24 | { | ||
25 | int i; | ||
26 | struct gpio_event_output_info *oi; | ||
27 | oi = container_of(info, struct gpio_event_output_info, info); | ||
28 | if (type != oi->type) | ||
29 | return 0; | ||
30 | if (!(oi->flags & GPIOEDF_ACTIVE_HIGH)) | ||
31 | value = !value; | ||
32 | for (i = 0; i < oi->keymap_size; i++) | ||
33 | if (dev == oi->keymap[i].dev && code == oi->keymap[i].code) | ||
34 | gpio_set_value(oi->keymap[i].gpio, value); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | int gpio_event_output_func( | ||
39 | struct gpio_event_input_devs *input_devs, struct gpio_event_info *info, | ||
40 | void **data, int func) | ||
41 | { | ||
42 | int ret; | ||
43 | int i; | ||
44 | struct gpio_event_output_info *oi; | ||
45 | oi = container_of(info, struct gpio_event_output_info, info); | ||
46 | |||
47 | if (func == GPIO_EVENT_FUNC_SUSPEND || func == GPIO_EVENT_FUNC_RESUME) | ||
48 | return 0; | ||
49 | |||
50 | if (func == GPIO_EVENT_FUNC_INIT) { | ||
51 | int output_level = !(oi->flags & GPIOEDF_ACTIVE_HIGH); | ||
52 | |||
53 | for (i = 0; i < oi->keymap_size; i++) { | ||
54 | int dev = oi->keymap[i].dev; | ||
55 | if (dev >= input_devs->count) { | ||
56 | pr_err("gpio_event_output_func: bad device " | ||
57 | "index %d >= %d for key code %d\n", | ||
58 | dev, input_devs->count, | ||
59 | oi->keymap[i].code); | ||
60 | ret = -EINVAL; | ||
61 | goto err_bad_keymap; | ||
62 | } | ||
63 | input_set_capability(input_devs->dev[dev], oi->type, | ||
64 | oi->keymap[i].code); | ||
65 | } | ||
66 | |||
67 | for (i = 0; i < oi->keymap_size; i++) { | ||
68 | ret = gpio_request(oi->keymap[i].gpio, | ||
69 | "gpio_event_output"); | ||
70 | if (ret) { | ||
71 | pr_err("gpio_event_output_func: gpio_request " | ||
72 | "failed for %d\n", oi->keymap[i].gpio); | ||
73 | goto err_gpio_request_failed; | ||
74 | } | ||
75 | ret = gpio_direction_output(oi->keymap[i].gpio, | ||
76 | output_level); | ||
77 | if (ret) { | ||
78 | pr_err("gpio_event_output_func: " | ||
79 | "gpio_direction_output failed for %d\n", | ||
80 | oi->keymap[i].gpio); | ||
81 | goto err_gpio_direction_output_failed; | ||
82 | } | ||
83 | } | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | ret = 0; | ||
88 | for (i = oi->keymap_size - 1; i >= 0; i--) { | ||
89 | err_gpio_direction_output_failed: | ||
90 | gpio_free(oi->keymap[i].gpio); | ||
91 | err_gpio_request_failed: | ||
92 | ; | ||
93 | } | ||
94 | err_bad_keymap: | ||
95 | return ret; | ||
96 | } | ||
97 | |||