aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/keyboard
diff options
context:
space:
mode:
authorKim Kyuwon <q1.kim@samsung.com>2009-09-22 01:17:04 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-09-22 01:26:40 -0400
commit0baf81ba157cb2b89448f0b73fcd9a4f191be8c6 (patch)
treeae3fe539cbd1543d6ed73b1b726912e770cfbf1a /drivers/input/keyboard
parent88751dd6ce1fb0627c36c4ab08a40730e5a50d3e (diff)
Input: add driver for Maxim MAX7359 key switch controller
The Maxim MAX7359 is a I2C interfaced key switch controller which provides microprocessors with management of up to 64 key switches. This patch adds support for the MAX7359 key switch controller. Signed-off-by: Kim Kyuwon <q1.kim@samsung.com> Reviewed-by: Trilok Soni <soni.trilok@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/keyboard')
-rw-r--r--drivers/input/keyboard/Kconfig11
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/max7359_keypad.c352
3 files changed, 364 insertions, 0 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index d615c09a83c6..57055bcbd7a6 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -261,6 +261,17 @@ config KEYBOARD_MAPLE
261 To compile this driver as a module, choose M here: the 261 To compile this driver as a module, choose M here: the
262 module will be called maple_keyb. 262 module will be called maple_keyb.
263 263
264config KEYBOARD_MAX7359
265 tristate "Maxim MAX7359 Key Switch Controller"
266 depends on I2C
267 help
268 If you say yes here you get support for the Maxim MAX7359 Key
269 Switch Controller chip. This providers microprocessors with
270 management of up to 64 key switches
271
272 To compile this driver as a module, choose M here: the
273 module will be called max7359_keypad.
274
264config KEYBOARD_NEWTON 275config KEYBOARD_NEWTON
265 tristate "Newton keyboard" 276 tristate "Newton keyboard"
266 select SERIO 277 select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index a5c08cdf8083..85ab894f613a 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
22obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o 22obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
23obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o 23obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
24obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o 24obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
25obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
25obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o 26obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
26obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o 27obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
27obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o 28obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
new file mode 100644
index 000000000000..8b3ee142a6c6
--- /dev/null
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -0,0 +1,352 @@
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
57struct max7359_keypad {
58 /* matrix key code map */
59 unsigned short keycodes[MAX7359_MAX_KEY_NUM];
60
61 struct work_struct work;
62
63 struct input_dev *input_dev;
64 struct i2c_client *client;
65
66 u32 irq;
67};
68
69static int max7359_write_reg(struct i2c_client *client, u8 reg, u8 val)
70{
71 int ret = i2c_smbus_write_byte_data(client, reg, val);
72
73 if (ret < 0)
74 dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
75 __func__, reg, val, ret);
76 return ret;
77}
78
79static int max7359_read_reg(struct i2c_client *client, int reg)
80{
81 int ret = i2c_smbus_read_byte_data(client, reg);
82
83 if (ret < 0)
84 dev_err(&client->dev, "%s: reg 0x%x, err %d\n",
85 __func__, reg, ret);
86 return ret;
87}
88
89static void max7359_build_keycode(struct max7359_keypad *keypad,
90 const struct matrix_keymap_data *keymap_data)
91{
92 struct input_dev *input_dev = keypad->input_dev;
93 int i;
94
95 for (i = 0; i < keymap_data->keymap_size; i++) {
96 unsigned int key = keymap_data->keymap[i];
97 unsigned int row = KEY_ROW(key);
98 unsigned int col = KEY_COL(key);
99 unsigned int scancode = MATRIX_SCAN_CODE(row, col,
100 MAX7359_ROW_SHIFT);
101 unsigned short keycode = KEY_VAL(key);
102
103 keypad->keycodes[scancode] = keycode;
104 __set_bit(keycode, input_dev->keybit);
105 }
106 __clear_bit(KEY_RESERVED, input_dev->keybit);
107}
108
109static void max7359_worker(struct work_struct *work)
110{
111 struct max7359_keypad *keypad =
112 container_of(work, struct max7359_keypad, work);
113 struct input_dev *input_dev = keypad->input_dev;
114 int val, row, col, release, code;
115
116 val = max7359_read_reg(keypad->client, MAX7359_REG_KEYFIFO);
117 row = val & 0x7;
118 col = (val >> 3) & 0x7;
119 release = val & 0x40;
120
121 code = MATRIX_SCAN_CODE(row, col, MAX7359_ROW_SHIFT);
122
123 input_event(input_dev, EV_MSC, MSC_SCAN, code);
124 input_report_key(input_dev, keypad->keycodes[code], !release);
125 input_sync(input_dev);
126
127 enable_irq(keypad->irq);
128
129 dev_dbg(&keypad->client->dev, "key[%d:%d] %s\n", row, col,
130 (release ? "release" : "press"));
131}
132
133static irqreturn_t max7359_interrupt(int irq, void *dev_id)
134{
135 struct max7359_keypad *keypad = dev_id;
136
137 if (!work_pending(&keypad->work)) {
138 disable_irq_nosync(keypad->irq);
139 schedule_work(&keypad->work);
140 }
141
142 return IRQ_HANDLED;
143}
144
145/*
146 * Let MAX7359 fall into a deep sleep:
147 * If no keys are pressed, enter sleep mode for 8192 ms. And if any
148 * key is pressed, the MAX7359 returns to normal operating mode.
149 */
150static inline void max7359_fall_deepsleep(struct i2c_client *client)
151{
152 max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_8192);
153}
154
155/*
156 * Let MAX7359 take a catnap:
157 * Autosleep just for 256 ms.
158 */
159static inline void max7359_take_catnap(struct i2c_client *client)
160{
161 max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_256);
162}
163
164static int max7359_open(struct input_dev *dev)
165{
166 struct max7359_keypad *keypad = input_get_drvdata(dev);
167
168 max7359_take_catnap(keypad->client);
169
170 return 0;
171}
172
173static void max7359_close(struct input_dev *dev)
174{
175 struct max7359_keypad *keypad = input_get_drvdata(dev);
176
177 max7359_fall_deepsleep(keypad->client);
178}
179
180static void max7359_initialize(struct i2c_client *client)
181{
182 max7359_write_reg(client, MAX7359_REG_CONFIG,
183 MAX7359_CFG_INTERRUPT | /* Irq clears after host read */
184 MAX7359_CFG_KEY_RELEASE | /* Key release enable */
185 MAX7359_CFG_WAKEUP); /* Key press wakeup enable */
186
187 /* Full key-scan functionality */
188 max7359_write_reg(client, MAX7359_REG_DEBOUNCE, 0x1F);
189
190 /* nINT asserts every debounce cycles */
191 max7359_write_reg(client, MAX7359_REG_INTERRUPT, 0x01);
192
193 max7359_fall_deepsleep(client);
194}
195
196static int __devinit max7359_probe(struct i2c_client *client,
197 const struct i2c_device_id *id)
198{
199 const struct matrix_keymap_data *keymap_data = client->dev.platform_data;
200 struct max7359_keypad *keypad;
201 struct input_dev *input_dev;
202 int ret;
203 int error;
204
205 if (!client->irq) {
206 dev_err(&client->dev, "The irq number should not be zero\n");
207 return -EINVAL;
208 }
209
210 /* Detect MAX7359: The initial Keys FIFO value is '0x3F' */
211 ret = max7359_read_reg(client, MAX7359_REG_KEYFIFO);
212 if (ret < 0) {
213 dev_err(&client->dev, "failed to detect device\n");
214 return -ENODEV;
215 }
216
217 dev_dbg(&client->dev, "keys FIFO is 0x%02x\n", ret);
218
219 keypad = kzalloc(sizeof(struct max7359_keypad), GFP_KERNEL);
220 input_dev = input_allocate_device();
221 if (!keypad || !input_dev) {
222 dev_err(&client->dev, "failed to allocate memory\n");
223 error = -ENOMEM;
224 goto failed_free_mem;
225 }
226
227 keypad->client = client;
228 keypad->input_dev = input_dev;
229 keypad->irq = client->irq;
230 INIT_WORK(&keypad->work, max7359_worker);
231
232 input_dev->name = client->name;
233 input_dev->id.bustype = BUS_I2C;
234 input_dev->open = max7359_open;
235 input_dev->close = max7359_close;
236 input_dev->dev.parent = &client->dev;
237
238 input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
239 input_dev->keycodesize = sizeof(keypad->keycodes[0]);
240 input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
241 input_dev->keycode = keypad->keycodes;
242
243 input_set_capability(input_dev, EV_MSC, MSC_SCAN);
244 input_set_drvdata(input_dev, keypad);
245
246 max7359_build_keycode(keypad, keymap_data);
247
248 error = request_irq(keypad->irq, max7359_interrupt,
249 IRQF_TRIGGER_LOW, client->name, keypad);
250 if (error) {
251 dev_err(&client->dev, "failed to register interrupt\n");
252 goto failed_free_mem;
253 }
254
255 /* Register the input device */
256 error = input_register_device(input_dev);
257 if (error) {
258 dev_err(&client->dev, "failed to register input device\n");
259 goto failed_free_irq;
260 }
261
262 /* Initialize MAX7359 */
263 max7359_initialize(client);
264
265 i2c_set_clientdata(client, keypad);
266 device_init_wakeup(&client->dev, 1);
267
268 return 0;
269
270failed_free_irq:
271 free_irq(keypad->irq, keypad);
272failed_free_mem:
273 input_free_device(input_dev);
274 kfree(keypad);
275 return error;
276}
277
278static int __devexit max7359_remove(struct i2c_client *client)
279{
280 struct max7359_keypad *keypad = i2c_get_clientdata(client);
281
282 cancel_work_sync(&keypad->work);
283 input_unregister_device(keypad->input_dev);
284 free_irq(keypad->irq, keypad);
285 i2c_set_clientdata(client, NULL);
286 kfree(keypad);
287
288 return 0;
289}
290
291#ifdef CONFIG_PM
292static int max7359_suspend(struct i2c_client *client, pm_message_t mesg)
293{
294 struct max7359_keypad *keypad = i2c_get_clientdata(client);
295
296 max7359_fall_deepsleep(client);
297
298 if (device_may_wakeup(&client->dev))
299 enable_irq_wake(keypad->irq);
300
301 return 0;
302}
303
304static int max7359_resume(struct i2c_client *client)
305{
306 struct max7359_keypad *keypad = i2c_get_clientdata(client);
307
308 if (device_may_wakeup(&client->dev))
309 disable_irq_wake(keypad->irq);
310
311 /* Restore the default setting */
312 max7359_take_catnap(client);
313
314 return 0;
315}
316#else
317#define max7359_suspend NULL
318#define max7359_resume NULL
319#endif
320
321static const struct i2c_device_id max7359_ids[] = {
322 { "max7359", 0 },
323 { }
324};
325MODULE_DEVICE_TABLE(i2c, max7359_ids);
326
327static struct i2c_driver max7359_i2c_driver = {
328 .driver = {
329 .name = "max7359",
330 },
331 .probe = max7359_probe,
332 .remove = __devexit_p(max7359_remove),
333 .suspend = max7359_suspend,
334 .resume = max7359_resume,
335 .id_table = max7359_ids,
336};
337
338static int __init max7359_init(void)
339{
340 return i2c_add_driver(&max7359_i2c_driver);
341}
342module_init(max7359_init);
343
344static void __exit max7359_exit(void)
345{
346 i2c_del_driver(&max7359_i2c_driver);
347}
348module_exit(max7359_exit);
349
350MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
351MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver");
352MODULE_LICENSE("GPL v2");