blob: ab38847d15e217d9197911e24ccc56a07fd14b97 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/board-mahimahi-keypad.c
2 *
3 * Copyright (C) 2009 Google, Inc
4 * Copyright (C) 2009 HTC Corporation.
5 *
6 * Author: Dima Zavin <dima@android.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/gpio_event.h>
19#include <linux/gpio.h>
20#include <linux/input.h>
21#include <linux/interrupt.h>
22#include <linux/keyreset.h>
23#include <linux/platform_device.h>
24#include <mach/vreg.h>
25
26#include <asm/mach-types.h>
27
28#include "board-mahimahi.h"
29
30struct jog_axis_info {
31 struct gpio_event_axis_info info;
32 uint16_t in_state;
33 uint16_t out_state;
34};
35
36static struct vreg *jog_vreg;
37static bool jog_just_on;
38static unsigned long jog_on_jiffies;
39
40static unsigned int mahimahi_col_gpios[] = { 33, 32, 31 };
41static unsigned int mahimahi_row_gpios[] = { 42, 41, 40 };
42
43#define KEYMAP_INDEX(col, row) ((col)*ARRAY_SIZE(mahimahi_row_gpios) + (row))
44#define KEYMAP_SIZE (ARRAY_SIZE(mahimahi_col_gpios) * \
45 ARRAY_SIZE(mahimahi_row_gpios))
46
47/* keypad */
48static const unsigned short mahimahi_keymap[KEYMAP_SIZE] = {
49 [KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
50 [KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
51 [KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
52};
53
54static const unsigned short mahimahi_cdma_keymap[KEYMAP_SIZE] = {
55 [KEYMAP_INDEX(0, 0)] = KEY_VOLUMEUP,
56 [KEYMAP_INDEX(0, 1)] = KEY_VOLUMEDOWN,
57 [KEYMAP_INDEX(1, 1)] = MATRIX_KEY(1, BTN_MOUSE),
58
59 /* Key (2, 2) is not a physical key on mahimahi. The purpose of
60 * registering the unused matrix key as a dummy <end> key is to make
61 * userland able to send/receive the key event for some requested tests
62 * in lab. of some CDMA carriers (e.g. Verizon).
63 */
64 [KEYMAP_INDEX(2, 2)] = KEY_END,
65};
66
67static struct gpio_event_matrix_info mahimahi_keypad_matrix_info = {
68 .info.func = gpio_event_matrix_func,
69 .keymap = mahimahi_keymap,
70 .output_gpios = mahimahi_col_gpios,
71 .input_gpios = mahimahi_row_gpios,
72 .noutputs = ARRAY_SIZE(mahimahi_col_gpios),
73 .ninputs = ARRAY_SIZE(mahimahi_row_gpios),
74 .settle_time.tv.nsec = 40 * NSEC_PER_USEC,
75 .poll_time.tv.nsec = 20 * NSEC_PER_MSEC,
76 .flags = (GPIOKPF_LEVEL_TRIGGERED_IRQ |
77 GPIOKPF_REMOVE_PHANTOM_KEYS |
78 GPIOKPF_PRINT_UNMAPPED_KEYS),
79};
80
81static struct gpio_event_direct_entry mahimahi_keypad_key_map[] = {
82 {
83 .gpio = MAHIMAHI_GPIO_POWER_KEY,
84 .code = KEY_POWER,
85 },
86};
87
88static struct gpio_event_input_info mahimahi_keypad_key_info = {
89 .info.func = gpio_event_input_func,
90 .info.no_suspend = true,
91 .debounce_time.tv.nsec = 5 * NSEC_PER_MSEC,
92 .flags = 0,
93 .type = EV_KEY,
94 .keymap = mahimahi_keypad_key_map,
95 .keymap_size = ARRAY_SIZE(mahimahi_keypad_key_map)
96};
97
98/* jogball */
99static uint16_t jogball_axis_map(struct gpio_event_axis_info *info, uint16_t in)
100{
101 struct jog_axis_info *ai =
102 container_of(info, struct jog_axis_info, info);
103 uint16_t out = ai->out_state;
104
105 if (jog_just_on) {
106 if (jiffies == jog_on_jiffies || jiffies == jog_on_jiffies + 1)
107 goto ignore;
108 jog_just_on = 0;
109 }
110 if((ai->in_state ^ in) & 1)
111 out--;
112 if((ai->in_state ^ in) & 2)
113 out++;
114 ai->out_state = out;
115ignore:
116 ai->in_state = in;
117 return out;
118}
119
120static int jogball_power(const struct gpio_event_platform_data *pdata, bool on)
121{
122 if (on) {
123 vreg_enable(jog_vreg);
124 jog_just_on = 1;
125 jog_on_jiffies = jiffies;
126 } else {
127 vreg_disable(jog_vreg);
128 }
129
130 return 0;
131}
132
133static int jogball_power_cdma(const struct gpio_event_platform_data *pdata, bool on)
134{
135 if (on) {
136 gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 1);
137 jog_just_on = 1;
138 jog_on_jiffies = jiffies;
139 } else {
140 gpio_set_value(MAHIMAHI_CDMA_JOG_2V6_EN, 0);
141 }
142
143 return 0;
144}
145
146static uint32_t jogball_x_gpios[] = {
147 MAHIMAHI_GPIO_BALL_LEFT, MAHIMAHI_GPIO_BALL_RIGHT,
148};
149static uint32_t jogball_y_gpios[] = {
150 MAHIMAHI_GPIO_BALL_UP, MAHIMAHI_GPIO_BALL_DOWN,
151};
152
153static struct jog_axis_info jogball_x_axis = {
154 .info = {
155 .info.func = gpio_event_axis_func,
156 .count = ARRAY_SIZE(jogball_x_gpios),
157 .dev = 1,
158 .type = EV_REL,
159 .code = REL_X,
160 .decoded_size = 1U << ARRAY_SIZE(jogball_x_gpios),
161 .map = jogball_axis_map,
162 .gpio = jogball_x_gpios,
163 .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
164 }
165};
166
167static struct jog_axis_info jogball_y_axis = {
168 .info = {
169 .info.func = gpio_event_axis_func,
170 .count = ARRAY_SIZE(jogball_y_gpios),
171 .dev = 1,
172 .type = EV_REL,
173 .code = REL_Y,
174 .decoded_size = 1U << ARRAY_SIZE(jogball_y_gpios),
175 .map = jogball_axis_map,
176 .gpio = jogball_y_gpios,
177 .flags = GPIOEAF_PRINT_UNKNOWN_DIRECTION,
178 }
179};
180
181static struct gpio_event_info *mahimahi_input_info[] = {
182 &mahimahi_keypad_matrix_info.info,
183 &mahimahi_keypad_key_info.info,
184 &jogball_x_axis.info.info,
185 &jogball_y_axis.info.info,
186};
187
188static struct gpio_event_platform_data mahimahi_input_data = {
189 .names = {
190 "mahimahi-keypad",
191 "mahimahi-nav",
192 NULL,
193 },
194 .info = mahimahi_input_info,
195 .info_count = ARRAY_SIZE(mahimahi_input_info),
196 .power = jogball_power,
197};
198
199static struct platform_device mahimahi_input_device = {
200 .name = GPIO_EVENT_DEV_NAME,
201 .id = 0,
202 .dev = {
203 .platform_data = &mahimahi_input_data,
204 },
205};
206
207static int mahimahi_reset_keys_up[] = {
208 KEY_VOLUMEUP,
209 0,
210};
211
212static struct keyreset_platform_data mahimahi_reset_keys_pdata = {
213 .keys_up = mahimahi_reset_keys_up,
214 .keys_down = {
215 KEY_POWER,
216 KEY_VOLUMEDOWN,
217 BTN_MOUSE,
218 0
219 },
220};
221
222struct platform_device mahimahi_reset_keys_device = {
223 .name = KEYRESET_NAME,
224 .dev = {
225 .platform_data = &mahimahi_reset_keys_pdata,
226 },
227};
228
229
230static int __init mahimahi_init_keypad_jogball(void)
231{
232 int ret;
233
234 if (!machine_is_mahimahi())
235 return 0;
236
237 ret = platform_device_register(&mahimahi_reset_keys_device);
238 if (ret != 0)
239 return ret;
240
241 if (is_cdma_version(system_rev)) {
242 mahimahi_keypad_matrix_info.keymap = mahimahi_cdma_keymap;
243 /* In the CDMA version, jogball power is supplied by a gpio. */
244 ret = gpio_request(MAHIMAHI_CDMA_JOG_2V6_EN, "jog_en");
245 if (ret < 0) {
246 pr_err("%s: gpio_request(%d) failed: %d\n", __func__,
247 MAHIMAHI_CDMA_JOG_2V6_EN, ret);
248 return ret;
249 }
250 mahimahi_input_data.power = jogball_power_cdma;
251 } else {
252 /* in UMTS version, jogball power is supplied by pmic */
253 jog_vreg = vreg_get(&mahimahi_input_device.dev, "gp2");
254 if (jog_vreg == NULL)
255 return -ENOENT;
256 }
257
258 ret = platform_device_register(&mahimahi_input_device);
259 if (ret != 0)
260 return ret;
261
262 return 0;
263}
264
265device_initcall(mahimahi_init_keypad_jogball);