Commit | Line | Data |
---|---|---|
0baf81ba KK |
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 work_struct work; | |
62 | ||
63 | struct input_dev *input_dev; | |
64 | struct i2c_client *client; | |
65 | ||
66 | u32 irq; | |
67 | }; | |
68 | ||
69 | static 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 | ||
79 | static 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 | ||
89 | static 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 | ||
109 | static 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 | ||
133 | static 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 | */ | |
150 | static 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 | */ | |
159 | static inline void max7359_take_catnap(struct i2c_client *client) | |
160 | { | |
161 | max7359_write_reg(client, MAX7359_REG_SLEEP, MAX7359_AUTOSLEEP_256); | |
162 | } | |
163 | ||
164 | static 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 | ||
173 | static 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 | ||
180 | static 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 | ||
196 | static 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 | ||
270 | failed_free_irq: | |
271 | free_irq(keypad->irq, keypad); | |
272 | failed_free_mem: | |
273 | input_free_device(input_dev); | |
274 | kfree(keypad); | |
275 | return error; | |
276 | } | |
277 | ||
278 | static 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 | |
292 | static 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 | ||
304 | static 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 | ||
321 | static const struct i2c_device_id max7359_ids[] = { | |
322 | { "max7359", 0 }, | |
323 | { } | |
324 | }; | |
325 | MODULE_DEVICE_TABLE(i2c, max7359_ids); | |
326 | ||
327 | static 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 | ||
338 | static int __init max7359_init(void) | |
339 | { | |
340 | return i2c_add_driver(&max7359_i2c_driver); | |
341 | } | |
342 | module_init(max7359_init); | |
343 | ||
344 | static void __exit max7359_exit(void) | |
345 | { | |
346 | i2c_del_driver(&max7359_i2c_driver); | |
347 | } | |
348 | module_exit(max7359_exit); | |
349 | ||
350 | MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>"); | |
351 | MODULE_DESCRIPTION("MAX7359 Key Switch Controller Driver"); | |
352 | MODULE_LICENSE("GPL v2"); |