1 /*
2  * SPEAr Keyboard Driver
3  * Based on omap-keypad driver
4  *
5  * Copyright (C) 2010 ST Microelectronics
6  * Rajeev Kumar<rajeev-dlh.kumar@st.com>
7  *
8  * This file is licensed under the terms of the GNU General Public
9  * License version 2. This program is licensed "as is" without any
10  * warranty of any kind, whether express or implied.
11  */
12 
13 #include <linux/clk.h>
14 #include <linux/errno.h>
15 #include <linux/init.h>
16 #include <linux/interrupt.h>
17 #include <linux/input.h>
18 #include <linux/io.h>
19 #include <linux/irq.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/platform_device.h>
23 #include <linux/pm_wakeup.h>
24 #include <linux/slab.h>
25 #include <linux/types.h>
26 #include <plat/keyboard.h>
27 
28 /* Keyboard Registers */
29 #define MODE_REG	0x00	/* 16 bit reg */
30 #define STATUS_REG	0x0C	/* 2 bit reg */
31 #define DATA_REG	0x10	/* 8 bit reg */
32 #define INTR_MASK	0x54
33 
34 /* Register Values */
35 /*
36  * pclk freq mask = (APB FEQ -1)= 82 MHZ.Programme bit 15-9 in mode
37  * control register as 1010010(82MHZ)
38  */
39 #define PCLK_FREQ_MSK	0xA400	/* 82 MHz */
40 #define START_SCAN	0x0100
41 #define SCAN_RATE_10	0x0000
42 #define SCAN_RATE_20	0x0004
43 #define SCAN_RATE_40	0x0008
44 #define SCAN_RATE_80	0x000C
45 #define MODE_KEYBOARD	0x0002
46 #define DATA_AVAIL	0x2
47 
48 #define KEY_MASK	0xFF000000
49 #define KEY_VALUE	0x00FFFFFF
50 #define ROW_MASK	0xF0
51 #define COLUMN_MASK	0x0F
52 #define ROW_SHIFT	4
53 #define KEY_MATRIX_SHIFT	6
54 
55 struct spear_kbd {
56 	struct input_dev *input;
57 	struct resource *res;
58 	void __iomem *io_base;
59 	struct clk *clk;
60 	unsigned int irq;
61 	unsigned int mode;
62 	unsigned short last_key;
63 	unsigned short keycodes[256];
64 };
65 
66 static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
67 {
68 	struct spear_kbd *kbd = dev_id;
69 	struct input_dev *input = kbd->input;
70 	unsigned int key;
71 	u8 sts, val;
72 
73 	sts = readb(kbd->io_base + STATUS_REG);
74 	if (!(sts & DATA_AVAIL))
75 		return IRQ_NONE;
76 
77 	if (kbd->last_key != KEY_RESERVED) {
78 		input_report_key(input, kbd->last_key, 0);
79 		kbd->last_key = KEY_RESERVED;
80 	}
81 
82 	/* following reads active (row, col) pair */
83 	val = readb(kbd->io_base + DATA_REG);
84 	key = kbd->keycodes[val];
85 
86 	input_event(input, EV_MSC, MSC_SCAN, val);
87 	input_report_key(input, key, 1);
88 	input_sync(input);
89 
90 	kbd->last_key = key;
91 
92 	/* clear interrupt */
93 	writeb(0, kbd->io_base + STATUS_REG);
94 
95 	return IRQ_HANDLED;
96 }
97 
98 static int spear_kbd_open(struct input_dev *dev)
99 {
100 	struct spear_kbd *kbd = input_get_drvdata(dev);
101 	int error;
102 	u16 val;
103 
104 	kbd->last_key = KEY_RESERVED;
105 
106 	error = clk_enable(kbd->clk);
107 	if (error)
108 		return error;
109 
110 	/* program keyboard */
111 	val = SCAN_RATE_80 | MODE_KEYBOARD | PCLK_FREQ_MSK |
112 		(kbd->mode << KEY_MATRIX_SHIFT);
113 	writew(val, kbd->io_base + MODE_REG);
114 	writeb(1, kbd->io_base + STATUS_REG);
115 
116 	/* start key scan */
117 	val = readw(kbd->io_base + MODE_REG);
118 	val |= START_SCAN;
119 	writew(val, kbd->io_base + MODE_REG);
120 
121 	return 0;
122 }
123 
124 static void spear_kbd_close(struct input_dev *dev)
125 {
126 	struct spear_kbd *kbd = input_get_drvdata(dev);
127 	u16 val;
128 
129 	/* stop key scan */
130 	val = readw(kbd->io_base + MODE_REG);
131 	val &= ~START_SCAN;
132 	writew(val, kbd->io_base + MODE_REG);
133 
134 	clk_disable(kbd->clk);
135 
136 	kbd->last_key = KEY_RESERVED;
137 }
138 
139 static int __devinit spear_kbd_probe(struct platform_device *pdev)
140 {
141 	const struct kbd_platform_data *pdata = pdev->dev.platform_data;
142 	const struct matrix_keymap_data *keymap;
143 	struct spear_kbd *kbd;
144 	struct input_dev *input_dev;
145 	struct resource *res;
146 	int irq;
147 	int error;
148 
149 	if (!pdata) {
150 		dev_err(&pdev->dev, "Invalid platform data\n");
151 		return -EINVAL;
152 	}
153 
154 	keymap = pdata->keymap;
155 	if (!keymap) {
156 		dev_err(&pdev->dev, "no keymap defined\n");
157 		return -EINVAL;
158 	}
159 
160 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
161 	if (!res) {
162 		dev_err(&pdev->dev, "no keyboard resource defined\n");
163 		return -EBUSY;
164 	}
165 
166 	irq = platform_get_irq(pdev, 0);
167 	if (irq < 0) {
168 		dev_err(&pdev->dev, "not able to get irq for the device\n");
169 		return irq;
170 	}
171 
172 	kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
173 	input_dev = input_allocate_device();
174 	if (!kbd || !input_dev) {
175 		dev_err(&pdev->dev, "out of memory\n");
176 		error = -ENOMEM;
177 		goto err_free_mem;
178 	}
179 
180 	kbd->input = input_dev;
181 	kbd->irq = irq;
182 	kbd->mode = pdata->mode;
183 
184 	kbd->res = request_mem_region(res->start, resource_size(res),
185 				      pdev->name);
186 	if (!kbd->res) {
187 		dev_err(&pdev->dev, "keyboard region already claimed\n");
188 		error = -EBUSY;
189 		goto err_free_mem;
190 	}
191 
192 	kbd->io_base = ioremap(res->start, resource_size(res));
193 	if (!kbd->io_base) {
194 		dev_err(&pdev->dev, "ioremap failed for kbd_region\n");
195 		error = -ENOMEM;
196 		goto err_release_mem_region;
197 	}
198 
199 	kbd->clk = clk_get(&pdev->dev, NULL);
200 	if (IS_ERR(kbd->clk)) {
201 		error = PTR_ERR(kbd->clk);
202 		goto err_iounmap;
203 	}
204 
205 	input_dev->name = "Spear Keyboard";
206 	input_dev->phys = "keyboard/input0";
207 	input_dev->dev.parent = &pdev->dev;
208 	input_dev->id.bustype = BUS_HOST;
209 	input_dev->id.vendor = 0x0001;
210 	input_dev->id.product = 0x0001;
211 	input_dev->id.version = 0x0100;
212 	input_dev->open = spear_kbd_open;
213 	input_dev->close = spear_kbd_close;
214 
215 	__set_bit(EV_KEY, input_dev->evbit);
216 	if (pdata->rep)
217 		__set_bit(EV_REP, input_dev->evbit);
218 	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
219 
220 	input_dev->keycode = kbd->keycodes;
221 	input_dev->keycodesize = sizeof(kbd->keycodes[0]);
222 	input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
223 
224 	matrix_keypad_build_keymap(keymap, ROW_SHIFT,
225 			input_dev->keycode, input_dev->keybit);
226 
227 	input_set_drvdata(input_dev, kbd);
228 
229 	error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
230 	if (error) {
231 		dev_err(&pdev->dev, "request_irq fail\n");
232 		goto err_put_clk;
233 	}
234 
235 	error = input_register_device(input_dev);
236 	if (error) {
237 		dev_err(&pdev->dev, "Unable to register keyboard device\n");
238 		goto err_free_irq;
239 	}
240 
241 	device_init_wakeup(&pdev->dev, 1);
242 	platform_set_drvdata(pdev, kbd);
243 
244 	return 0;
245 
246 err_free_irq:
247 	free_irq(kbd->irq, kbd);
248 err_put_clk:
249 	clk_put(kbd->clk);
250 err_iounmap:
251 	iounmap(kbd->io_base);
252 err_release_mem_region:
253 	release_mem_region(res->start, resource_size(res));
254 err_free_mem:
255 	input_free_device(input_dev);
256 	kfree(kbd);
257 
258 	return error;
259 }
260 
261 static int __devexit spear_kbd_remove(struct platform_device *pdev)
262 {
263 	struct spear_kbd *kbd = platform_get_drvdata(pdev);
264 
265 	free_irq(kbd->irq, kbd);
266 	input_unregister_device(kbd->input);
267 	clk_put(kbd->clk);
268 	iounmap(kbd->io_base);
269 	release_mem_region(kbd->res->start, resource_size(kbd->res));
270 	kfree(kbd);
271 
272 	device_init_wakeup(&pdev->dev, 1);
273 	platform_set_drvdata(pdev, NULL);
274 
275 	return 0;
276 }
277 
278 #ifdef CONFIG_PM
279 static int spear_kbd_suspend(struct device *dev)
280 {
281 	struct platform_device *pdev = to_platform_device(dev);
282 	struct spear_kbd *kbd = platform_get_drvdata(pdev);
283 	struct input_dev *input_dev = kbd->input;
284 
285 	mutex_lock(&input_dev->mutex);
286 
287 	if (input_dev->users)
288 		clk_enable(kbd->clk);
289 
290 	if (device_may_wakeup(&pdev->dev))
291 		enable_irq_wake(kbd->irq);
292 
293 	mutex_unlock(&input_dev->mutex);
294 
295 	return 0;
296 }
297 
298 static int spear_kbd_resume(struct device *dev)
299 {
300 	struct platform_device *pdev = to_platform_device(dev);
301 	struct spear_kbd *kbd = platform_get_drvdata(pdev);
302 	struct input_dev *input_dev = kbd->input;
303 
304 	mutex_lock(&input_dev->mutex);
305 
306 	if (device_may_wakeup(&pdev->dev))
307 		disable_irq_wake(kbd->irq);
308 
309 	if (input_dev->users)
310 		clk_enable(kbd->clk);
311 
312 	mutex_unlock(&input_dev->mutex);
313 
314 	return 0;
315 }
316 #endif
317 
318 static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
319 
320 static struct platform_driver spear_kbd_driver = {
321 	.probe		= spear_kbd_probe,
322 	.remove		= __devexit_p(spear_kbd_remove),
323 	.driver		= {
324 		.name	= "keyboard",
325 		.owner	= THIS_MODULE,
326 		.pm	= &spear_kbd_pm_ops,
327 	},
328 };
329 module_platform_driver(spear_kbd_driver);
330 
331 MODULE_AUTHOR("Rajeev Kumar");
332 MODULE_DESCRIPTION("SPEAr Keyboard Driver");
333 MODULE_LICENSE("GPL");
334