1bab7614dSEric Miao /*
2bab7614dSEric Miao  *  GPIO driven matrix keyboard driver
3bab7614dSEric Miao  *
4bab7614dSEric Miao  *  Copyright (c) 2008 Marek Vasut <marek.vasut@gmail.com>
5bab7614dSEric Miao  *
6bab7614dSEric Miao  *  Based on corgikbd.c
7bab7614dSEric Miao  *
8bab7614dSEric Miao  *  This program is free software; you can redistribute it and/or modify
9bab7614dSEric Miao  *  it under the terms of the GNU General Public License version 2 as
10bab7614dSEric Miao  *  published by the Free Software Foundation.
11bab7614dSEric Miao  *
12bab7614dSEric Miao  */
13bab7614dSEric Miao 
14bab7614dSEric Miao #include <linux/types.h>
15bab7614dSEric Miao #include <linux/delay.h>
16bab7614dSEric Miao #include <linux/platform_device.h>
17bab7614dSEric Miao #include <linux/init.h>
18bab7614dSEric Miao #include <linux/input.h>
19bab7614dSEric Miao #include <linux/irq.h>
20bab7614dSEric Miao #include <linux/interrupt.h>
21bab7614dSEric Miao #include <linux/jiffies.h>
22bab7614dSEric Miao #include <linux/module.h>
23bab7614dSEric Miao #include <linux/gpio.h>
24bab7614dSEric Miao #include <linux/input/matrix_keypad.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
264a83eecfSAnilKumar Ch #include <linux/of.h>
274a83eecfSAnilKumar Ch #include <linux/of_gpio.h>
284a83eecfSAnilKumar Ch #include <linux/of_platform.h>
29bab7614dSEric Miao 
30bab7614dSEric Miao struct matrix_keypad {
31bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata;
32bab7614dSEric Miao 	struct input_dev *input_dev;
33d82f1c35SEric Miao 	unsigned int row_shift;
34bab7614dSEric Miao 
35dd219234SDmitry Torokhov 	DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
36dd219234SDmitry Torokhov 
37bab7614dSEric Miao 	uint32_t last_key_state[MATRIX_MAX_COLS];
38bab7614dSEric Miao 	struct delayed_work work;
39dd219234SDmitry Torokhov 	spinlock_t lock;
40bab7614dSEric Miao 	bool scan_pending;
41bab7614dSEric Miao 	bool stopped;
42fb76dd10SLuotao Fu 	bool gpio_all_disabled;
43bab7614dSEric Miao };
44bab7614dSEric Miao 
45bab7614dSEric Miao /*
46bab7614dSEric Miao  * NOTE: normally the GPIO has to be put into HiZ when de-activated to cause
47bab7614dSEric Miao  * minmal side effect when scanning other columns, here it is configured to
48bab7614dSEric Miao  * be input, and it should work on most platforms.
49bab7614dSEric Miao  */
50bab7614dSEric Miao static void __activate_col(const struct matrix_keypad_platform_data *pdata,
51bab7614dSEric Miao 			   int col, bool on)
52bab7614dSEric Miao {
53bab7614dSEric Miao 	bool level_on = !pdata->active_low;
54bab7614dSEric Miao 
55bab7614dSEric Miao 	if (on) {
56bab7614dSEric Miao 		gpio_direction_output(pdata->col_gpios[col], level_on);
57bab7614dSEric Miao 	} else {
58bab7614dSEric Miao 		gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);
59bab7614dSEric Miao 		gpio_direction_input(pdata->col_gpios[col]);
60bab7614dSEric Miao 	}
61bab7614dSEric Miao }
62bab7614dSEric Miao 
63bab7614dSEric Miao static void activate_col(const struct matrix_keypad_platform_data *pdata,
64bab7614dSEric Miao 			 int col, bool on)
65bab7614dSEric Miao {
66bab7614dSEric Miao 	__activate_col(pdata, col, on);
67bab7614dSEric Miao 
68bab7614dSEric Miao 	if (on && pdata->col_scan_delay_us)
69bab7614dSEric Miao 		udelay(pdata->col_scan_delay_us);
70bab7614dSEric Miao }
71bab7614dSEric Miao 
72bab7614dSEric Miao static void activate_all_cols(const struct matrix_keypad_platform_data *pdata,
73bab7614dSEric Miao 			      bool on)
74bab7614dSEric Miao {
75bab7614dSEric Miao 	int col;
76bab7614dSEric Miao 
77bab7614dSEric Miao 	for (col = 0; col < pdata->num_col_gpios; col++)
78bab7614dSEric Miao 		__activate_col(pdata, col, on);
79bab7614dSEric Miao }
80bab7614dSEric Miao 
81bab7614dSEric Miao static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
82bab7614dSEric Miao 			 int row)
83bab7614dSEric Miao {
84bab7614dSEric Miao 	return gpio_get_value_cansleep(pdata->row_gpios[row]) ?
85bab7614dSEric Miao 			!pdata->active_low : pdata->active_low;
86bab7614dSEric Miao }
87bab7614dSEric Miao 
88bab7614dSEric Miao static void enable_row_irqs(struct matrix_keypad *keypad)
89bab7614dSEric Miao {
90bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
91bab7614dSEric Miao 	int i;
92bab7614dSEric Miao 
93fb76dd10SLuotao Fu 	if (pdata->clustered_irq > 0)
94fb76dd10SLuotao Fu 		enable_irq(pdata->clustered_irq);
95fb76dd10SLuotao Fu 	else {
96bab7614dSEric Miao 		for (i = 0; i < pdata->num_row_gpios; i++)
97bab7614dSEric Miao 			enable_irq(gpio_to_irq(pdata->row_gpios[i]));
98bab7614dSEric Miao 	}
99fb76dd10SLuotao Fu }
100bab7614dSEric Miao 
101bab7614dSEric Miao static void disable_row_irqs(struct matrix_keypad *keypad)
102bab7614dSEric Miao {
103bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
104bab7614dSEric Miao 	int i;
105bab7614dSEric Miao 
106fb76dd10SLuotao Fu 	if (pdata->clustered_irq > 0)
107fb76dd10SLuotao Fu 		disable_irq_nosync(pdata->clustered_irq);
108fb76dd10SLuotao Fu 	else {
109bab7614dSEric Miao 		for (i = 0; i < pdata->num_row_gpios; i++)
110bab7614dSEric Miao 			disable_irq_nosync(gpio_to_irq(pdata->row_gpios[i]));
111bab7614dSEric Miao 	}
112fb76dd10SLuotao Fu }
113bab7614dSEric Miao 
114bab7614dSEric Miao /*
115bab7614dSEric Miao  * This gets the keys from keyboard and reports it to input subsystem
116bab7614dSEric Miao  */
117bab7614dSEric Miao static void matrix_keypad_scan(struct work_struct *work)
118bab7614dSEric Miao {
119bab7614dSEric Miao 	struct matrix_keypad *keypad =
120bab7614dSEric Miao 		container_of(work, struct matrix_keypad, work.work);
121bab7614dSEric Miao 	struct input_dev *input_dev = keypad->input_dev;
1224a83eecfSAnilKumar Ch 	const unsigned short *keycodes = input_dev->keycode;
123bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
124bab7614dSEric Miao 	uint32_t new_state[MATRIX_MAX_COLS];
125bab7614dSEric Miao 	int row, col, code;
126bab7614dSEric Miao 
127bab7614dSEric Miao 	/* de-activate all columns for scanning */
128bab7614dSEric Miao 	activate_all_cols(pdata, false);
129bab7614dSEric Miao 
130bab7614dSEric Miao 	memset(new_state, 0, sizeof(new_state));
131bab7614dSEric Miao 
132bab7614dSEric Miao 	/* assert each column and read the row status out */
133bab7614dSEric Miao 	for (col = 0; col < pdata->num_col_gpios; col++) {
134bab7614dSEric Miao 
135bab7614dSEric Miao 		activate_col(pdata, col, true);
136bab7614dSEric Miao 
137bab7614dSEric Miao 		for (row = 0; row < pdata->num_row_gpios; row++)
138bab7614dSEric Miao 			new_state[col] |=
139bab7614dSEric Miao 				row_asserted(pdata, row) ? (1 << row) : 0;
140bab7614dSEric Miao 
141bab7614dSEric Miao 		activate_col(pdata, col, false);
142bab7614dSEric Miao 	}
143bab7614dSEric Miao 
144bab7614dSEric Miao 	for (col = 0; col < pdata->num_col_gpios; col++) {
145bab7614dSEric Miao 		uint32_t bits_changed;
146bab7614dSEric Miao 
147bab7614dSEric Miao 		bits_changed = keypad->last_key_state[col] ^ new_state[col];
148bab7614dSEric Miao 		if (bits_changed == 0)
149bab7614dSEric Miao 			continue;
150bab7614dSEric Miao 
151bab7614dSEric Miao 		for (row = 0; row < pdata->num_row_gpios; row++) {
152bab7614dSEric Miao 			if ((bits_changed & (1 << row)) == 0)
153bab7614dSEric Miao 				continue;
154bab7614dSEric Miao 
155d82f1c35SEric Miao 			code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
156bab7614dSEric Miao 			input_event(input_dev, EV_MSC, MSC_SCAN, code);
157bab7614dSEric Miao 			input_report_key(input_dev,
1584a83eecfSAnilKumar Ch 					 keycodes[code],
159bab7614dSEric Miao 					 new_state[col] & (1 << row));
160bab7614dSEric Miao 		}
161bab7614dSEric Miao 	}
162bab7614dSEric Miao 	input_sync(input_dev);
163bab7614dSEric Miao 
164bab7614dSEric Miao 	memcpy(keypad->last_key_state, new_state, sizeof(new_state));
165bab7614dSEric Miao 
166bab7614dSEric Miao 	activate_all_cols(pdata, true);
167bab7614dSEric Miao 
168bab7614dSEric Miao 	/* Enable IRQs again */
169bab7614dSEric Miao 	spin_lock_irq(&keypad->lock);
170bab7614dSEric Miao 	keypad->scan_pending = false;
171bab7614dSEric Miao 	enable_row_irqs(keypad);
172bab7614dSEric Miao 	spin_unlock_irq(&keypad->lock);
173bab7614dSEric Miao }
174bab7614dSEric Miao 
175bab7614dSEric Miao static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
176bab7614dSEric Miao {
177bab7614dSEric Miao 	struct matrix_keypad *keypad = id;
178bab7614dSEric Miao 	unsigned long flags;
179bab7614dSEric Miao 
180bab7614dSEric Miao 	spin_lock_irqsave(&keypad->lock, flags);
181bab7614dSEric Miao 
182bab7614dSEric Miao 	/*
183bab7614dSEric Miao 	 * See if another IRQ beaten us to it and scheduled the
184bab7614dSEric Miao 	 * scan already. In that case we should not try to
185bab7614dSEric Miao 	 * disable IRQs again.
186bab7614dSEric Miao 	 */
187bab7614dSEric Miao 	if (unlikely(keypad->scan_pending || keypad->stopped))
188bab7614dSEric Miao 		goto out;
189bab7614dSEric Miao 
190bab7614dSEric Miao 	disable_row_irqs(keypad);
191bab7614dSEric Miao 	keypad->scan_pending = true;
192bab7614dSEric Miao 	schedule_delayed_work(&keypad->work,
193bab7614dSEric Miao 		msecs_to_jiffies(keypad->pdata->debounce_ms));
194bab7614dSEric Miao 
195bab7614dSEric Miao out:
196bab7614dSEric Miao 	spin_unlock_irqrestore(&keypad->lock, flags);
197bab7614dSEric Miao 	return IRQ_HANDLED;
198bab7614dSEric Miao }
199bab7614dSEric Miao 
200bab7614dSEric Miao static int matrix_keypad_start(struct input_dev *dev)
201bab7614dSEric Miao {
202bab7614dSEric Miao 	struct matrix_keypad *keypad = input_get_drvdata(dev);
203bab7614dSEric Miao 
204bab7614dSEric Miao 	keypad->stopped = false;
205bab7614dSEric Miao 	mb();
206bab7614dSEric Miao 
207bab7614dSEric Miao 	/*
208bab7614dSEric Miao 	 * Schedule an immediate key scan to capture current key state;
209bab7614dSEric Miao 	 * columns will be activated and IRQs be enabled after the scan.
210bab7614dSEric Miao 	 */
211bab7614dSEric Miao 	schedule_delayed_work(&keypad->work, 0);
212bab7614dSEric Miao 
213bab7614dSEric Miao 	return 0;
214bab7614dSEric Miao }
215bab7614dSEric Miao 
216bab7614dSEric Miao static void matrix_keypad_stop(struct input_dev *dev)
217bab7614dSEric Miao {
218bab7614dSEric Miao 	struct matrix_keypad *keypad = input_get_drvdata(dev);
219bab7614dSEric Miao 
220bab7614dSEric Miao 	keypad->stopped = true;
221bab7614dSEric Miao 	mb();
222bab7614dSEric Miao 	flush_work(&keypad->work.work);
223bab7614dSEric Miao 	/*
224bab7614dSEric Miao 	 * matrix_keypad_scan() will leave IRQs enabled;
225bab7614dSEric Miao 	 * we should disable them now.
226bab7614dSEric Miao 	 */
227bab7614dSEric Miao 	disable_row_irqs(keypad);
228bab7614dSEric Miao }
229bab7614dSEric Miao 
2300508c19aSDmitry Torokhov #ifdef CONFIG_PM_SLEEP
231fb76dd10SLuotao Fu static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
232bab7614dSEric Miao {
233bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
234fb76dd10SLuotao Fu 	unsigned int gpio;
235bab7614dSEric Miao 	int i;
236bab7614dSEric Miao 
237fb76dd10SLuotao Fu 	if (pdata->clustered_irq > 0) {
238fb76dd10SLuotao Fu 		if (enable_irq_wake(pdata->clustered_irq) == 0)
239fb76dd10SLuotao Fu 			keypad->gpio_all_disabled = true;
240fb76dd10SLuotao Fu 	} else {
241bab7614dSEric Miao 
242dd219234SDmitry Torokhov 		for (i = 0; i < pdata->num_row_gpios; i++) {
243dd219234SDmitry Torokhov 			if (!test_bit(i, keypad->disabled_gpios)) {
244fb76dd10SLuotao Fu 				gpio = pdata->row_gpios[i];
245dd219234SDmitry Torokhov 
246dd219234SDmitry Torokhov 				if (enable_irq_wake(gpio_to_irq(gpio)) == 0)
247dd219234SDmitry Torokhov 					__set_bit(i, keypad->disabled_gpios);
248dd219234SDmitry Torokhov 			}
249dd219234SDmitry Torokhov 		}
250dd219234SDmitry Torokhov 	}
251fb76dd10SLuotao Fu }
252fb76dd10SLuotao Fu 
253fb76dd10SLuotao Fu static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
254fb76dd10SLuotao Fu {
255fb76dd10SLuotao Fu 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
256fb76dd10SLuotao Fu 	unsigned int gpio;
257fb76dd10SLuotao Fu 	int i;
258fb76dd10SLuotao Fu 
259fb76dd10SLuotao Fu 	if (pdata->clustered_irq > 0) {
260fb76dd10SLuotao Fu 		if (keypad->gpio_all_disabled) {
261fb76dd10SLuotao Fu 			disable_irq_wake(pdata->clustered_irq);
262fb76dd10SLuotao Fu 			keypad->gpio_all_disabled = false;
263fb76dd10SLuotao Fu 		}
264fb76dd10SLuotao Fu 	} else {
265fb76dd10SLuotao Fu 		for (i = 0; i < pdata->num_row_gpios; i++) {
266fb76dd10SLuotao Fu 			if (test_and_clear_bit(i, keypad->disabled_gpios)) {
267fb76dd10SLuotao Fu 				gpio = pdata->row_gpios[i];
268fb76dd10SLuotao Fu 				disable_irq_wake(gpio_to_irq(gpio));
269fb76dd10SLuotao Fu 			}
270fb76dd10SLuotao Fu 		}
271fb76dd10SLuotao Fu 	}
272fb76dd10SLuotao Fu }
273fb76dd10SLuotao Fu 
274fb76dd10SLuotao Fu static int matrix_keypad_suspend(struct device *dev)
275fb76dd10SLuotao Fu {
276fb76dd10SLuotao Fu 	struct platform_device *pdev = to_platform_device(dev);
277fb76dd10SLuotao Fu 	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
278fb76dd10SLuotao Fu 
279fb76dd10SLuotao Fu 	matrix_keypad_stop(keypad->input_dev);
280fb76dd10SLuotao Fu 
281fb76dd10SLuotao Fu 	if (device_may_wakeup(&pdev->dev))
282fb76dd10SLuotao Fu 		matrix_keypad_enable_wakeup(keypad);
283bab7614dSEric Miao 
284bab7614dSEric Miao 	return 0;
285bab7614dSEric Miao }
286bab7614dSEric Miao 
287f72a28abSDmitry Torokhov static int matrix_keypad_resume(struct device *dev)
288bab7614dSEric Miao {
289f72a28abSDmitry Torokhov 	struct platform_device *pdev = to_platform_device(dev);
290bab7614dSEric Miao 	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
291bab7614dSEric Miao 
292fb76dd10SLuotao Fu 	if (device_may_wakeup(&pdev->dev))
293fb76dd10SLuotao Fu 		matrix_keypad_disable_wakeup(keypad);
294bab7614dSEric Miao 
295bab7614dSEric Miao 	matrix_keypad_start(keypad->input_dev);
296bab7614dSEric Miao 
297bab7614dSEric Miao 	return 0;
298bab7614dSEric Miao }
299bab7614dSEric Miao #endif
300bab7614dSEric Miao 
3010508c19aSDmitry Torokhov static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
3020508c19aSDmitry Torokhov 			 matrix_keypad_suspend, matrix_keypad_resume);
3030508c19aSDmitry Torokhov 
304b83643ebSDmitry Torokhov static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
305bab7614dSEric Miao 					     struct matrix_keypad *keypad)
306bab7614dSEric Miao {
307bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
308b83643ebSDmitry Torokhov 	int i, err;
309bab7614dSEric Miao 
310bab7614dSEric Miao 	/* initialized strobe lines as outputs, activated */
311bab7614dSEric Miao 	for (i = 0; i < pdata->num_col_gpios; i++) {
312bab7614dSEric Miao 		err = gpio_request(pdata->col_gpios[i], "matrix_kbd_col");
313bab7614dSEric Miao 		if (err) {
314bab7614dSEric Miao 			dev_err(&pdev->dev,
315bab7614dSEric Miao 				"failed to request GPIO%d for COL%d\n",
316bab7614dSEric Miao 				pdata->col_gpios[i], i);
317bab7614dSEric Miao 			goto err_free_cols;
318bab7614dSEric Miao 		}
319bab7614dSEric Miao 
320bab7614dSEric Miao 		gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
321bab7614dSEric Miao 	}
322bab7614dSEric Miao 
323bab7614dSEric Miao 	for (i = 0; i < pdata->num_row_gpios; i++) {
324bab7614dSEric Miao 		err = gpio_request(pdata->row_gpios[i], "matrix_kbd_row");
325bab7614dSEric Miao 		if (err) {
326bab7614dSEric Miao 			dev_err(&pdev->dev,
327bab7614dSEric Miao 				"failed to request GPIO%d for ROW%d\n",
328bab7614dSEric Miao 				pdata->row_gpios[i], i);
329bab7614dSEric Miao 			goto err_free_rows;
330bab7614dSEric Miao 		}
331bab7614dSEric Miao 
332bab7614dSEric Miao 		gpio_direction_input(pdata->row_gpios[i]);
333bab7614dSEric Miao 	}
334bab7614dSEric Miao 
335fb76dd10SLuotao Fu 	if (pdata->clustered_irq > 0) {
336fb76dd10SLuotao Fu 		err = request_irq(pdata->clustered_irq,
337fb76dd10SLuotao Fu 				matrix_keypad_interrupt,
338fb76dd10SLuotao Fu 				pdata->clustered_irq_flags,
339fb76dd10SLuotao Fu 				"matrix-keypad", keypad);
340fb76dd10SLuotao Fu 		if (err) {
341fb76dd10SLuotao Fu 			dev_err(&pdev->dev,
342fb76dd10SLuotao Fu 				"Unable to acquire clustered interrupt\n");
343fb76dd10SLuotao Fu 			goto err_free_rows;
344fb76dd10SLuotao Fu 		}
345fb76dd10SLuotao Fu 	} else {
346bab7614dSEric Miao 		for (i = 0; i < pdata->num_row_gpios; i++) {
347bab7614dSEric Miao 			err = request_irq(gpio_to_irq(pdata->row_gpios[i]),
348bab7614dSEric Miao 					matrix_keypad_interrupt,
349fb76dd10SLuotao Fu 					IRQF_TRIGGER_RISING |
350fb76dd10SLuotao Fu 					IRQF_TRIGGER_FALLING,
351bab7614dSEric Miao 					"matrix-keypad", keypad);
352bab7614dSEric Miao 			if (err) {
353bab7614dSEric Miao 				dev_err(&pdev->dev,
354b83643ebSDmitry Torokhov 					"Unable to acquire interrupt for GPIO line %i\n",
355bab7614dSEric Miao 					pdata->row_gpios[i]);
356bab7614dSEric Miao 				goto err_free_irqs;
357bab7614dSEric Miao 			}
358bab7614dSEric Miao 		}
359fb76dd10SLuotao Fu 	}
360bab7614dSEric Miao 
361bab7614dSEric Miao 	/* initialized as disabled - enabled by input->open */
362bab7614dSEric Miao 	disable_row_irqs(keypad);
363bab7614dSEric Miao 	return 0;
364bab7614dSEric Miao 
365bab7614dSEric Miao err_free_irqs:
366bab7614dSEric Miao 	while (--i >= 0)
367bab7614dSEric Miao 		free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
368bab7614dSEric Miao 	i = pdata->num_row_gpios;
369bab7614dSEric Miao err_free_rows:
370bab7614dSEric Miao 	while (--i >= 0)
371bab7614dSEric Miao 		gpio_free(pdata->row_gpios[i]);
372bab7614dSEric Miao 	i = pdata->num_col_gpios;
373bab7614dSEric Miao err_free_cols:
374bab7614dSEric Miao 	while (--i >= 0)
375bab7614dSEric Miao 		gpio_free(pdata->col_gpios[i]);
376bab7614dSEric Miao 
377bab7614dSEric Miao 	return err;
378bab7614dSEric Miao }
379bab7614dSEric Miao 
380b83643ebSDmitry Torokhov static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
381b83643ebSDmitry Torokhov {
382b83643ebSDmitry Torokhov 	const struct matrix_keypad_platform_data *pdata = keypad->pdata;
383b83643ebSDmitry Torokhov 	int i;
384b83643ebSDmitry Torokhov 
385b83643ebSDmitry Torokhov 	if (pdata->clustered_irq > 0) {
386b83643ebSDmitry Torokhov 		free_irq(pdata->clustered_irq, keypad);
387b83643ebSDmitry Torokhov 	} else {
388b83643ebSDmitry Torokhov 		for (i = 0; i < pdata->num_row_gpios; i++)
389b83643ebSDmitry Torokhov 			free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
390b83643ebSDmitry Torokhov 	}
391b83643ebSDmitry Torokhov 
392b83643ebSDmitry Torokhov 	for (i = 0; i < pdata->num_row_gpios; i++)
393b83643ebSDmitry Torokhov 		gpio_free(pdata->row_gpios[i]);
394b83643ebSDmitry Torokhov 
395b83643ebSDmitry Torokhov 	for (i = 0; i < pdata->num_col_gpios; i++)
396b83643ebSDmitry Torokhov 		gpio_free(pdata->col_gpios[i]);
397b83643ebSDmitry Torokhov }
398b83643ebSDmitry Torokhov 
3994a83eecfSAnilKumar Ch #ifdef CONFIG_OF
4004a83eecfSAnilKumar Ch static struct matrix_keypad_platform_data * __devinit
4014a83eecfSAnilKumar Ch matrix_keypad_parse_dt(struct device *dev)
4024a83eecfSAnilKumar Ch {
4034a83eecfSAnilKumar Ch 	struct matrix_keypad_platform_data *pdata;
4044a83eecfSAnilKumar Ch 	struct device_node *np = dev->of_node;
4054a83eecfSAnilKumar Ch 	unsigned int *gpios;
4064a83eecfSAnilKumar Ch 	int i;
4074a83eecfSAnilKumar Ch 
4084a83eecfSAnilKumar Ch 	if (!np) {
4094a83eecfSAnilKumar Ch 		dev_err(dev, "device lacks DT data\n");
4104a83eecfSAnilKumar Ch 		return ERR_PTR(-ENODEV);
4114a83eecfSAnilKumar Ch 	}
4124a83eecfSAnilKumar Ch 
4134a83eecfSAnilKumar Ch 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
4144a83eecfSAnilKumar Ch 	if (!pdata) {
4154a83eecfSAnilKumar Ch 		dev_err(dev, "could not allocate memory for platform data\n");
4164a83eecfSAnilKumar Ch 		return ERR_PTR(-ENOMEM);
4174a83eecfSAnilKumar Ch 	}
4184a83eecfSAnilKumar Ch 
4194a83eecfSAnilKumar Ch 	pdata->num_row_gpios = of_gpio_named_count(np, "row-gpios");
4204a83eecfSAnilKumar Ch 	pdata->num_col_gpios = of_gpio_named_count(np, "col-gpios");
4214a83eecfSAnilKumar Ch 	if (!pdata->num_row_gpios || !pdata->num_col_gpios) {
4224a83eecfSAnilKumar Ch 		dev_err(dev, "number of keypad rows/columns not specified\n");
4234a83eecfSAnilKumar Ch 		return ERR_PTR(-EINVAL);
4244a83eecfSAnilKumar Ch 	}
4254a83eecfSAnilKumar Ch 
4264a83eecfSAnilKumar Ch 	if (of_get_property(np, "linux,no-autorepeat", NULL))
4274a83eecfSAnilKumar Ch 		pdata->no_autorepeat = true;
4284a83eecfSAnilKumar Ch 	if (of_get_property(np, "linux,wakeup", NULL))
4294a83eecfSAnilKumar Ch 		pdata->wakeup = true;
4304a83eecfSAnilKumar Ch 	if (of_get_property(np, "gpio-activelow", NULL))
4314a83eecfSAnilKumar Ch 		pdata->active_low = true;
4324a83eecfSAnilKumar Ch 
4334a83eecfSAnilKumar Ch 	of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
4344a83eecfSAnilKumar Ch 	of_property_read_u32(np, "col-scan-delay-us",
4354a83eecfSAnilKumar Ch 						&pdata->col_scan_delay_us);
4364a83eecfSAnilKumar Ch 
4374a83eecfSAnilKumar Ch 	gpios = devm_kzalloc(dev,
4384a83eecfSAnilKumar Ch 			     sizeof(unsigned int) *
4394a83eecfSAnilKumar Ch 				(pdata->num_row_gpios + pdata->num_col_gpios),
4404a83eecfSAnilKumar Ch 			     GFP_KERNEL);
4414a83eecfSAnilKumar Ch 	if (!gpios) {
4424a83eecfSAnilKumar Ch 		dev_err(dev, "could not allocate memory for gpios\n");
4434a83eecfSAnilKumar Ch 		return ERR_PTR(-ENOMEM);
4444a83eecfSAnilKumar Ch 	}
4454a83eecfSAnilKumar Ch 
4464a83eecfSAnilKumar Ch 	for (i = 0; i < pdata->num_row_gpios; i++)
4474a83eecfSAnilKumar Ch 		gpios[i] = of_get_named_gpio(np, "row-gpios", i);
4484a83eecfSAnilKumar Ch 
4494a83eecfSAnilKumar Ch 	for (i = 0; i < pdata->num_col_gpios; i++)
4504a83eecfSAnilKumar Ch 		gpios[pdata->num_row_gpios + i] =
4514a83eecfSAnilKumar Ch 			of_get_named_gpio(np, "col-gpios", i);
4524a83eecfSAnilKumar Ch 
4534a83eecfSAnilKumar Ch 	pdata->row_gpios = gpios;
4544a83eecfSAnilKumar Ch 	pdata->col_gpios = &gpios[pdata->num_row_gpios];
4554a83eecfSAnilKumar Ch 
4564a83eecfSAnilKumar Ch 	return pdata;
4574a83eecfSAnilKumar Ch }
4584a83eecfSAnilKumar Ch #else
4594a83eecfSAnilKumar Ch static inline struct matrix_keypad_platform_data *
4604a83eecfSAnilKumar Ch matrix_keypad_parse_dt(struct device *dev)
4614a83eecfSAnilKumar Ch {
4624a83eecfSAnilKumar Ch 	dev_err(dev, "no platform data defined\n");
4634a83eecfSAnilKumar Ch 
4644a83eecfSAnilKumar Ch 	return ERR_PTR(-EINVAL);
4654a83eecfSAnilKumar Ch }
4664a83eecfSAnilKumar Ch #endif
4674a83eecfSAnilKumar Ch 
468bab7614dSEric Miao static int __devinit matrix_keypad_probe(struct platform_device *pdev)
469bab7614dSEric Miao {
470bab7614dSEric Miao 	const struct matrix_keypad_platform_data *pdata;
471bab7614dSEric Miao 	struct matrix_keypad *keypad;
472bab7614dSEric Miao 	struct input_dev *input_dev;
473bab7614dSEric Miao 	int err;
474bab7614dSEric Miao 
4754a83eecfSAnilKumar Ch 	pdata = dev_get_platdata(&pdev->dev);
476bab7614dSEric Miao 	if (!pdata) {
4774a83eecfSAnilKumar Ch 		pdata = matrix_keypad_parse_dt(&pdev->dev);
4784a83eecfSAnilKumar Ch 		if (IS_ERR(pdata)) {
479bab7614dSEric Miao 			dev_err(&pdev->dev, "no platform data defined\n");
4804a83eecfSAnilKumar Ch 			return PTR_ERR(pdata);
481bab7614dSEric Miao 		}
4824a83eecfSAnilKumar Ch 	} else if (!pdata->keymap_data) {
483bab7614dSEric Miao 		dev_err(&pdev->dev, "no keymap data defined\n");
484bab7614dSEric Miao 		return -EINVAL;
485bab7614dSEric Miao 	}
486bab7614dSEric Miao 
4874a83eecfSAnilKumar Ch 	keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
488bab7614dSEric Miao 	input_dev = input_allocate_device();
48901111fcdSDmitry Torokhov 	if (!keypad || !input_dev) {
490bab7614dSEric Miao 		err = -ENOMEM;
491bab7614dSEric Miao 		goto err_free_mem;
492bab7614dSEric Miao 	}
493bab7614dSEric Miao 
494bab7614dSEric Miao 	keypad->input_dev = input_dev;
495bab7614dSEric Miao 	keypad->pdata = pdata;
4964a83eecfSAnilKumar Ch 	keypad->row_shift = get_count_order(pdata->num_col_gpios);
497bab7614dSEric Miao 	keypad->stopped = true;
498bab7614dSEric Miao 	INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
499bab7614dSEric Miao 	spin_lock_init(&keypad->lock);
500bab7614dSEric Miao 
501bab7614dSEric Miao 	input_dev->name		= pdev->name;
502bab7614dSEric Miao 	input_dev->id.bustype	= BUS_HOST;
503bab7614dSEric Miao 	input_dev->dev.parent	= &pdev->dev;
504bab7614dSEric Miao 	input_dev->open		= matrix_keypad_start;
505bab7614dSEric Miao 	input_dev->close	= matrix_keypad_stop;
506bab7614dSEric Miao 
5074a83eecfSAnilKumar Ch 	err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
5081932811fSDmitry Torokhov 					 pdata->num_row_gpios,
5091932811fSDmitry Torokhov 					 pdata->num_col_gpios,
5104a83eecfSAnilKumar Ch 					 NULL, input_dev);
5114a83eecfSAnilKumar Ch 	if (err) {
5124a83eecfSAnilKumar Ch 		dev_err(&pdev->dev, "failed to build keymap\n");
5131932811fSDmitry Torokhov 		goto err_free_mem;
5144a83eecfSAnilKumar Ch 	}
515bab7614dSEric Miao 
5161932811fSDmitry Torokhov 	if (!pdata->no_autorepeat)
5171932811fSDmitry Torokhov 		__set_bit(EV_REP, input_dev->evbit);
518bab7614dSEric Miao 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
519bab7614dSEric Miao 	input_set_drvdata(input_dev, keypad);
520bab7614dSEric Miao 
521b83643ebSDmitry Torokhov 	err = matrix_keypad_init_gpio(pdev, keypad);
522bab7614dSEric Miao 	if (err)
523bab7614dSEric Miao 		goto err_free_mem;
524bab7614dSEric Miao 
525bab7614dSEric Miao 	err = input_register_device(keypad->input_dev);
526bab7614dSEric Miao 	if (err)
527b83643ebSDmitry Torokhov 		goto err_free_gpio;
528bab7614dSEric Miao 
529bab7614dSEric Miao 	device_init_wakeup(&pdev->dev, pdata->wakeup);
530bab7614dSEric Miao 	platform_set_drvdata(pdev, keypad);
531bab7614dSEric Miao 
532bab7614dSEric Miao 	return 0;
533bab7614dSEric Miao 
534b83643ebSDmitry Torokhov err_free_gpio:
535b83643ebSDmitry Torokhov 	matrix_keypad_free_gpio(keypad);
536bab7614dSEric Miao err_free_mem:
537bab7614dSEric Miao 	input_free_device(input_dev);
538bab7614dSEric Miao 	kfree(keypad);
539bab7614dSEric Miao 	return err;
540bab7614dSEric Miao }
541bab7614dSEric Miao 
542bab7614dSEric Miao static int __devexit matrix_keypad_remove(struct platform_device *pdev)
543bab7614dSEric Miao {
544bab7614dSEric Miao 	struct matrix_keypad *keypad = platform_get_drvdata(pdev);
545bab7614dSEric Miao 
546bab7614dSEric Miao 	device_init_wakeup(&pdev->dev, 0);
547bab7614dSEric Miao 
548b83643ebSDmitry Torokhov 	matrix_keypad_free_gpio(keypad);
549bab7614dSEric Miao 	input_unregister_device(keypad->input_dev);
550bab7614dSEric Miao 	kfree(keypad);
551bab7614dSEric Miao 
552b83643ebSDmitry Torokhov 	platform_set_drvdata(pdev, NULL);
553b83643ebSDmitry Torokhov 
554bab7614dSEric Miao 	return 0;
555bab7614dSEric Miao }
556bab7614dSEric Miao 
5574a83eecfSAnilKumar Ch #ifdef CONFIG_OF
5584a83eecfSAnilKumar Ch static const struct of_device_id matrix_keypad_dt_match[] = {
5594a83eecfSAnilKumar Ch 	{ .compatible = "gpio-matrix-keypad" },
5604a83eecfSAnilKumar Ch 	{ }
5614a83eecfSAnilKumar Ch };
5624a83eecfSAnilKumar Ch MODULE_DEVICE_TABLE(of, matrix_keypad_dt_match);
5634a83eecfSAnilKumar Ch #endif
5644a83eecfSAnilKumar Ch 
565bab7614dSEric Miao static struct platform_driver matrix_keypad_driver = {
566bab7614dSEric Miao 	.probe		= matrix_keypad_probe,
5671cb0aa88SBill Pemberton 	.remove		= matrix_keypad_remove,
568bab7614dSEric Miao 	.driver		= {
569bab7614dSEric Miao 		.name	= "matrix-keypad",
570bab7614dSEric Miao 		.owner	= THIS_MODULE,
571f72a28abSDmitry Torokhov 		.pm	= &matrix_keypad_pm_ops,
5724a83eecfSAnilKumar Ch 		.of_match_table = of_match_ptr(matrix_keypad_dt_match),
573bab7614dSEric Miao 	},
574bab7614dSEric Miao };
5755146c84fSJJ Ding module_platform_driver(matrix_keypad_driver);
576bab7614dSEric Miao 
577bab7614dSEric Miao MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
578bab7614dSEric Miao MODULE_DESCRIPTION("GPIO Driven Matrix Keypad Driver");
579bab7614dSEric Miao MODULE_LICENSE("GPL v2");
580bab7614dSEric Miao MODULE_ALIAS("platform:matrix-keypad");
581