diff options
Diffstat (limited to 'drivers/input/keyboard/max7359_keypad.c')
-rw-r--r-- | drivers/input/keyboard/max7359_keypad.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c new file mode 100644 index 000000000000..3b5b948eba39 --- /dev/null +++ b/drivers/input/keyboard/max7359_keypad.c | |||
@@ -0,0 +1,330 @@ | |||
1 | /* | ||
2 | * max7359_keypad.c - MAX7359 Key Switch Controller Driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics | ||
5 | * Kim Kyuwon <q1.kim@samsung.com> | ||
6 | * | ||
7 | * Based on pxa27x_keypad.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * Datasheet: http://www.maxim-ic.com/quick_view2.cfm/qv_pk/5456 | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/input.h> | ||
20 | #include <linux/input/matrix_keypad.h> | ||
21 | |||
22 | #define MAX7359_MAX_KEY_ROWS 8 | ||
23 | #define MAX7359_MAX_KEY_COLS 8 | ||
24 | #define MAX7359_MAX_KEY_NUM (MAX7359_MAX_KEY_ROWS * MAX7359_MAX_KEY_COLS) | ||
25 | #define MAX7359_ROW_SHIFT 3 | ||
26 | |||
27 | /* | ||
28 | * MAX7359 registers | ||
29 | */ | ||
30 | #define MAX7359_REG_KEYFIFO 0x00 | ||
31 | #define MAX7359_REG_CONFIG 0x01 | ||
32 | #define MAX7359_REG_DEBOUNCE 0x02 | ||
33 | #define MAX7359_REG_INTERRUPT 0x03 | ||
34 | #define MAX7359_REG_PORTS 0x04 | ||
35 | #define MAX7359_REG_KEYREP 0x05 | ||
36 | #define MAX7359_REG_SLEEP 0x06 | ||
37 | |||
38 | /* | ||
39 | * Configuration register bits | ||
40 | */ | ||
41 | #define MAX7359_CFG_SLEEP (1 << 7) | ||
42 | #define MAX7359_CFG_INTERRUPT (1 << 5) | ||
43 | #define MAX7359_CFG_KEY_RELEASE (1 << 3) | ||
44 | #define MAX7359_CFG_WAKEUP (1 << 1) | ||
45 | #define MAX7359_CFG_TIMEOUT (1 << 0) | ||
46 | |||
47 | /* | ||
48 | * Autosleep register values (ms) | ||
49 | */ | ||
50 | #define MAX7359_AUTOSLEEP_8192 0x01 | ||
51 | #define MAX7359_AUTOSLEEP_4096 0x02 | ||
52 | #define MAX7359_AUTOSLEEP_2048 0x03 | ||
53 | #define MAX7359_AUTOSLEEP_1024 0x04 | ||
54 | #define MAX7359_AUTOSLEEP_512 0x05 | ||
55 | #define MAX7359_AUTOSLEEP_256 0x06 | ||
56 | |||
57 | struct max7359_keypad { | ||
58 | /* matrix key code map */ | ||
59 | unsigned short keycodes[MAX7359_MAX_KEY_NUM]; | ||
60 | |||
61 | struct input_dev *input_dev; | ||
62 | struct i2c_client *client; | ||
63 | }; | ||
64 | |||
65 | static int max7359_write_reg(struct i2c_client *client, u8 reg, u8 val) | ||
66 | { | ||
67 | int ret = i2c_smbus_write_byte_data(client, reg, val); | ||
68 | |||
69 | if (ret < 0) | ||
70 | dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", | ||
71 | __func__, reg, val, ret); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static int max7359_read_reg(struct i2c_client *client, int reg) | ||
76 | { | ||
77 | int ret = i2c_smbus_read_byte_data(client, reg); | ||
78 | |||
79 | if (ret < 0) | ||
80 | dev_err(&client->dev, "%s: reg 0x%x, err %d\n", | ||
81 | __func__, reg, ret); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | static void max7359_build_keycode(struct max7359_keypad *keypad, | ||
86 | const struct matrix_keymap_data *keymap_data) | ||
87 | { | ||
88 | struct input_dev *input_dev = keypad->input_dev; | ||
89 | int i; | ||
90 | |||
91 | for (i = 0; i < keymap_data->keymap_size; i++) { | ||
92 | unsigned int key = keymap_data->keymap[i]; | ||
93 | unsigned int row = KEY_ROW(key); | ||
94 | unsigned int col = KEY_COL(key); | ||
95 | unsigned int scancode = MATRIX_SCAN_CODE(row, col, | ||
96 | MAX7359_ROW_SHIFT); | ||
97 | unsigned short keycode = KEY_VAL(key); | ||
98 | |||
99 | keypad->keycodes[scancode] = keycode; | ||
100 | __set_bit(keycode, input_dev->keybit); | ||
101 | } | ||
102 | __clear_bit(KEY_RESERVED, input_dev->keybit); | ||
103 | } | ||
104 | |||
105 | /* runs in an IRQ thread -- can (and will!) sleep */ | ||
106 | static irqreturn_t max7359_interrupt(int irq, void *dev_id) | ||
107 | { | ||
108 | struct max7359_keypad *keypad = dev_id; | ||
109 | struct input_dev *input_dev = keypad->input_dev; | ||
110 | int val, row, col, release, code; | ||
111 | |||
112 | val = max7359_read_reg(keypad->client, MAX7359_REG_KEYFIFO); | ||
113 | row = val & 0x7; | ||
114 | col = (val >> 3) & 0x7; | ||
115 | release = val & 0x40; | ||
116 | |||
117 | code = MATRIX_SCAN_CODE(row, col, MAX7359_ROW_SHIFT); | ||
118 | |||
119 | dev_dbg(&keypad->client->dev, | ||
120 | "key[%d:%d] %s\n", row, col, release ? "release" : "press"); | ||
121 | |||
122 | input_event(input_dev, EV_MSC, MSC_SCAN, code); | ||
123 | input_report_key(input_dev, keypad->keycodes[code], !release); | ||
124 | input_sync(input_dev); | ||
125 | |||
126 | return IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Let MAX7359 fall into a deep sleep: | ||
131 | * If no keys are pressed, enter sleep mode for 8192 ms. And if any | ||
132 | * key is pressed, the MAX7359 returns to normal operating mode. | ||
133 | */ | ||
134 | static inline void max7359_fall_deepsleep(struct i2c_client *client) | ||
135 | { | ||
136 | max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_8192); | ||
137 | } | ||
138 | |||
139 | /* | ||
140 | * Let MAX7359 take a catnap: | ||
141 | * Autosleep just for 256 ms. | ||
142 | */ | ||
143 | static inline void max7359_take_catnap(struct i2c_client *client) | ||
144 | { | ||
145 | max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_256); | ||
146 | } | ||
147 | |||
148 | static int max7359_open(struct input_dev *dev) | ||
149 | { | ||
150 | struct max7359_keypad *keypad = input_get_drvdata(dev); | ||
151 | |||
152 | max7359_take_catnap(keypad->client); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static void max7359_close(struct input_dev *dev) | ||
158 | { | ||
159 | struct max7359_keypad *keypad = input_get_drvdata(dev); | ||
160 | |||
161 | max7359_fall_deepsleep(keypad->client); | ||
162 | } | ||
163 | |||
164 | static void max7359_initialize(struct i2c_client *client) | ||
165 | { | ||
166 | max7359_write_reg(client, MAX7359_REG_CONFIG, | ||
167 | MAX7359_CFG_INTERRUPT | /* Irq clears after host read */ | ||
168 | MAX7359_CFG_KEY_RELEASE | /* Key release enable */ | ||
169 | MAX7359_CFG_WAKEUP); /* Key press wakeup enable */ | ||
170 | |||
171 | /* Full key-scan functionality */ | ||
172 | max7359_write_reg(client, MAX7359_REG_DEBOUNCE, 0x1F); | ||
173 | |||
174 | /* nINT asserts every debounce cycles */ | ||
175 | max7359_write_reg(client, MAX7359_REG_INTERRUPT, 0x01); | ||
176 | |||
177 | max7359_fall_deepsleep(client); | ||
178 | } | ||
179 | |||
180 | static int __devinit max7359_probe(struct i2c_client *client, | ||
181 | const struct i2c_device_id *id) | ||
182 | { | ||
183 | const struct matrix_keymap_data *keymap_data = client->dev.platform_data; | ||
184 | struct max7359_keypad *keypad; | ||
185 | struct input_dev *input_dev; | ||
186 | int ret; | ||
187 | int error; | ||
188 | |||
189 | if (!client->irq) { | ||
190 | dev_err(&client->dev, "The irq number should not be zero\n"); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | /* Detect MAX7359: The initial Keys FIFO value is '0x3F' */ | ||
195 | ret = max7359_read_reg(client, MAX7359_REG_KEYFIFO); | ||
196 | if (ret < 0) { | ||
197 | dev_err(&client->dev, "failed to detect device\n"); | ||
198 | return -ENODEV; | ||
199 | } | ||
200 | |||
201 | dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret); | ||
202 | |||
203 | keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL); | ||
204 | input_dev = input_allocate_device(); | ||
205 | if (!keypad || !input_dev) { | ||
206 | dev_err(&client->dev, "failed to allocate memory\n"); | ||
207 | error = -ENOMEM; | ||
208 | goto failed_free_mem; | ||
209 | } | ||
210 | |||
211 | keypad->client = client; | ||
212 | keypad->input_dev = input_dev; | ||
213 | |||
214 | input_dev->name = client->name; | ||
215 | input_dev->id.bustype = BUS_I2C; | ||
216 | input_dev->open = max7359_open; | ||
217 | input_dev->close = max7359_close; | ||
218 | input_dev->dev.parent = &client->dev; | ||
219 | |||
220 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); | ||
221 | input_dev->keycodesize = sizeof(keypad->keycodes[0]); | ||
222 | input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes); | ||
223 | input_dev->keycode = keypad->keycodes; | ||
224 | |||
225 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
226 | input_set_drvdata(input_dev, keypad); | ||
227 | |||
228 | max7359_build_keycode(keypad, keymap_data); | ||
229 | |||
230 | error = request_threaded_irq(client->irq, NULL, max7359_interrupt, | ||
231 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
232 | client->name, keypad); | ||
233 | if (error) { | ||
234 | dev_err(&client->dev, "failed to register interrupt\n"); | ||
235 | goto failed_free_mem; | ||
236 | } | ||
237 | |||
238 | /* Register the input device */ | ||
239 | error = input_register_device(input_dev); | ||
240 | if (error) { | ||
241 | dev_err(&client->dev, "failed to register input device\n"); | ||
242 | goto failed_free_irq; | ||
243 | } | ||
244 | |||
245 | /* Initialize MAX7359 */ | ||
246 | max7359_initialize(client); | ||
247 | |||
248 | i2c_set_clientdata(client, keypad); | ||
249 | device_init_wakeup(&client->dev, 1); | ||
250 | |||
251 | return 0; | ||
252 | |||
253 | failed_free_irq: | ||
254 | free_irq(client->irq, keypad); | ||
255 | failed_free_mem: | ||
256 | input_free_device(input_dev); | ||
257 | kfree(keypad); | ||
258 | return error; | ||
259 | } | ||
260 | |||
261 | static int __devexit max7359_remove(struct i2c_client *client) | ||
262 | { | ||
263 | struct max7359_keypad *keypad = i2c_get_clientdata(client); | ||
264 | |||
265 | free_irq(client->irq, keypad); | ||
266 | input_unregister_device(keypad->input_dev); | ||
267 | i2c_set_clientdata(client, NULL); | ||
268 | kfree(keypad); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | #ifdef CONFIG_PM | ||
274 | static int max7359_suspend(struct i2c_client *client, pm_message_t mesg) | ||
275 | { | ||
276 | max7359_fall_deepsleep(client); | ||
277 | |||
278 | if (device_may_wakeup(&client->dev)) | ||
279 | enable_irq_wake(client->irq); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int max7359_resume(struct i2c_client *client) | ||
285 | { | ||
286 | if (device_may_wakeup(&client->dev)) | ||
287 | disable_irq_wake(client->irq); | ||
288 | |||
289 | /* Restore the default setting */ | ||
290 | max7359_take_catnap(client); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | #else | ||
295 | #define max7359_suspend NULL | ||
296 | #define max7359_resume NULL | ||
297 | #endif | ||
298 | |||
299 | static const struct i2c_device_id max7359_ids[] = { | ||
300 | { "max7359", 0 }, | ||
301 | { } | ||
302 | }; | ||
303 | MODULE_DEVICE_TABLE(i2c, max7359_ids); | ||
304 | |||
305 | static struct i2c_driver max7359_i2c_driver = { | ||
306 | .driver = { | ||
307 | .name = "max7359", | ||
308 | }, | ||
309 | .probe = max7359_probe, | ||
310 | .remove = __devexit_p(max7359_remove), | ||
311 | .suspend = max7359_suspend, | ||
312 | .resume = max7359_resume, | ||
313 | .id_table = max7359_ids, | ||
314 | }; | ||
315 | |||
316 | static int __init max7359_init(void) | ||
317 | { | ||
318 | return i2c_add_driver(&max7359_i2c_driver); | ||
319 | } | ||
320 | module_init(max7359_init); | ||
321 | |||
322 | static void __exit max7359_exit(void) | ||
323 | { | ||
324 | i2c_del_driver(&max7359_i2c_driver); | ||
325 | } | ||
326 | module_exit(max7359_exit); | ||
327 | |||
328 | MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); | ||
329 | MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver"); | ||
330 | MODULE_LICENSE("GPL v2"); | ||