Merge branch 'v2.6.34-rc7.iommu' of git://gitorious.org/~doyu/lk/mainline into omap...
[pandora-kernel.git] / drivers / input / serio / ams_delta_serio.c
1 /*
2  *  Amstrad E3 (Delta) keyboard port driver
3  *
4  *  Copyright (c) 2006 Matt Callow
5  *  Copyright (c) 2010 Janusz Krzysztofik
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * Thanks to Cliff Lawson for his help
12  *
13  * The Amstrad Delta keyboard (aka mailboard) uses normal PC-AT style serial
14  * transmission.  The keyboard port is formed of two GPIO lines, for clock
15  * and data.  Due to strict timing requirements of the interface,
16  * the serial data stream is read and processed by a FIQ handler.
17  * The resulting words are fetched by this driver from a circular buffer.
18  *
19  * Standard AT keyboard driver (atkbd) is used for handling the keyboard data.
20  * However, when used with the E3 mailboard that producecs non-standard
21  * scancodes, a custom key table must be prepared and loaded from userspace.
22  */
23 #include <linux/gpio.h>
24 #include <linux/irq.h>
25 #include <linux/serio.h>
26 #include <linux/slab.h>
27
28 #include <asm/mach-types.h>
29 #include <plat/board-ams-delta.h>
30
31 #include <mach/ams-delta-fiq.h>
32
33 MODULE_AUTHOR("Matt Callow");
34 MODULE_DESCRIPTION("AMS Delta (E3) keyboard port driver");
35 MODULE_LICENSE("GPL");
36
37 static struct serio *ams_delta_serio;
38
39 static int check_data(int data)
40 {
41         int i, parity = 0;
42
43         /* check valid stop bit */
44         if (!(data & 0x400)) {
45                 dev_warn(&ams_delta_serio->dev,
46                                 "invalid stop bit, data=0x%X\n",
47                                 data);
48                 return SERIO_FRAME;
49         }
50         /* calculate the parity */
51         for (i = 1; i < 10; i++) {
52                 if (data & (1 << i))
53                         parity++;
54         }
55         /* it should be odd */
56         if (!(parity & 0x01)) {
57                 dev_warn(&ams_delta_serio->dev,
58                                 "paritiy check failed, data=0x%X parity=0x%X\n",
59                                 data, parity);
60                 return SERIO_PARITY;
61         }
62         return 0;
63 }
64
65 static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id)
66 {
67         int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF];
68         int data, dfl;
69         u8 scancode;
70
71         fiq_buffer[FIQ_IRQ_PEND] = 0;
72
73         /*
74          * Read data from the circular buffer, check it
75          * and then pass it on the serio
76          */
77         while (fiq_buffer[FIQ_KEYS_CNT] > 0) {
78
79                 data = circ_buff[fiq_buffer[FIQ_HEAD_OFFSET]++];
80                 fiq_buffer[FIQ_KEYS_CNT]--;
81                 if (fiq_buffer[FIQ_HEAD_OFFSET] == fiq_buffer[FIQ_BUF_LEN])
82                         fiq_buffer[FIQ_HEAD_OFFSET] = 0;
83
84                 dfl = check_data(data);
85                 scancode = (u8) (data >> 1) & 0xFF;
86                 serio_interrupt(ams_delta_serio, scancode, dfl);
87         }
88         return IRQ_HANDLED;
89 }
90
91 static int ams_delta_serio_open(struct serio *serio)
92 {
93         /* enable keyboard */
94         ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR,
95                         AMD_DELTA_LATCH2_KEYBRD_PWR);
96
97         return 0;
98 }
99
100 static void ams_delta_serio_close(struct serio *serio)
101 {
102         /* disable keyboard */
103         ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR, 0);
104 }
105
106 static int __init ams_delta_serio_init(void)
107 {
108         int err;
109
110         if (!machine_is_ams_delta())
111                 return -ENODEV;
112
113         ams_delta_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
114         if (!ams_delta_serio)
115                 return -ENOMEM;
116
117         ams_delta_serio->id.type = SERIO_8042;
118         ams_delta_serio->open = ams_delta_serio_open;
119         ams_delta_serio->close = ams_delta_serio_close;
120         strlcpy(ams_delta_serio->name, "AMS DELTA keyboard adapter",
121                         sizeof(ams_delta_serio->name));
122         strlcpy(ams_delta_serio->phys, "GPIO/serio0",
123                         sizeof(ams_delta_serio->phys));
124
125         err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_DATA, "serio-data");
126         if (err) {
127                 pr_err("ams_delta_serio: Couldn't request gpio pin for data\n");
128                 goto serio;
129         }
130         gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
131
132         err = gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_CLK, "serio-clock");
133         if (err) {
134                 pr_err("ams_delta_serio: couldn't request gpio pin for clock\n");
135                 goto gpio_data;
136         }
137         gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
138
139         err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
140                         ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING,
141                         "ams-delta-serio", 0);
142         if (err < 0) {
143                 pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n",
144                                 gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
145                 goto gpio_clk;
146         }
147         /*
148          * Since GPIO register handling for keyboard clock pin is performed
149          * at FIQ level, switch back from edge to simple interrupt handler
150          * to avoid bad interaction.
151          */
152         set_irq_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
153                         handle_simple_irq);
154
155         serio_register_port(ams_delta_serio);
156         dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name);
157
158         return 0;
159 gpio_clk:
160         gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
161 gpio_data:
162         gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
163 serio:
164         kfree(ams_delta_serio);
165         return err;
166 }
167 module_init(ams_delta_serio_init);
168
169 static void __exit ams_delta_serio_exit(void)
170 {
171         serio_unregister_port(ams_delta_serio);
172         free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
173         gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
174         gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
175         kfree(ams_delta_serio);
176 }
177 module_exit(ams_delta_serio_exit);