hh.org updates
[hh.org.git] / arch / arm / mach-pxa / h4000 / h4300_kbd.c
blob39bfd6ae5a3230b0b883bb56fd4acc02a33fb1cd
1 /*
2 * h4300_kbd.c
3 * Keyboard support for the h4350 ipaq
5 * (c) Shawn Anderson, March, 2006
6 * This code is released under the GNU General Public License
8 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10 #include <linux/platform_device.h>
11 #include <linux/delay.h>
12 #include <linux/input.h>
13 #include <linux/input_pda.h>
14 #include <linux/interrupt.h>
15 #include <linux/irq.h>
16 #include <asm/arch/h4000-gpio.h>
17 #include <asm/arch/h4000-asic.h>
18 #include <linux/soc/asic3_base.h>
19 #include <asm/arch/pxa-regs.h>
20 #include <asm/hardware.h>
21 #include <asm/arch/bitfield.h>
23 int h4000_machine_is_h4300(void);
24 static struct input_dev *h4300_kbd;
25 #define a3 &h4000_asic3.dev
27 #define KEY_FUNC 0x32
28 static unsigned int h4300_keycode[0x80] = {
29 /*0*/ 0, 0, 0, 0, 0, 0, 0, 0,
30 0, 0, _KEY_CALENDAR, _KEY_CONTACTS,
31 0, 0, _KEY_MAIL, _KEY_HOMEPAGE,
32 /*1*/ KEY_R, KEY_RIGHT, KEY_W, KEY_E,
33 KEY_SELECT, KEY_U, KEY_I, KEY_P,
34 KEY_F, KEY_Y, KEY_Q, KEY_D,
35 KEY_DOWN, KEY_K, KEY_O, KEY_BACKSPACE,
36 /*2*/ KEY_X, KEY_H, KEY_A, KEY_S,
37 KEY_T, KEY_J, KEY_L, KEY_ENTER,
38 KEY_C, KEY_B, KEY_LEFTSHIFT, KEY_Z,
39 KEY_G, KEY_M, KEY_1, KEY_APOSTROPHE,
40 /*3*/ KEY_ESC, KEY_SPACE, 0/*KEY_FUNC*/, KEY_TAB,
41 KEY_V, KEY_N, KEY_COMMA, KEY_SLASH,
42 KEY_LEFT, KEY_UP, 0, 0,
43 KEY_LEFTCTRL, KEY_DOT, 0, 0,
44 /*4*/ 0, 0, 0, 0, 0, 0, 0, 0,
45 0, 0, KEY_PROG1, KEY_PROG2,
46 0, 0, KEY_PROG3, KEY_PROG4,
47 /*5*/ KEY_5, KEY_RIGHT, KEY_2, KEY_4,
48 KEY_SELECT, KEY_1, KEY_2, KEY_SLASH,
49 KEY_EQUAL, KEY_MINUS, KEY_GRAVE, KEY_SEMICOLON,
50 KEY_DOWN, KEY_5, KEY_3, KEY_DELETE,
51 /*6*/ KEY_SEMICOLON, KEY_KPPLUS, KEY_9, KEY_0,
52 KEY_MINUS, KEY_4, KEY_6, KEY_ENTER,
53 KEY_LEFT, KEY_RIGHT, KEY_CAPSLOCK, KEY_7,
54 KEY_UP, KEY_8, KEY_9, KEY_APOSTROPHE,
55 /*7*/ KEY_ESC, KEY_COMPOSE, 0/*KEY_FUNC*/, KEY_TAB,
56 KEY_DOWN, KEY_7, KEY_0, KEY_3,
57 KEY_LEFT, KEY_UP, 0, 0,
58 KEY_BACKSLASH, KEY_KPASTERISK, 0, 0
61 static int asic3_spi_process_byte(unsigned char data)
63 #define ASIC3_SPI_CTRL (_IPAQ_ASIC3_SPI_Base + _IPAQ_ASIC3_SPI_Control)
64 #define ASIC3_SPI_TXDATA (_IPAQ_ASIC3_SPI_Base + _IPAQ_ASIC3_SPI_TxData)
65 #define ASIC3_SPI_RXDATA (_IPAQ_ASIC3_SPI_Base + _IPAQ_ASIC3_SPI_RxData)
66 #define SPI_CTRL_SEL (1 << 6)
67 #define SPI_CTRL_SPIE (1 << 5)
68 #define SPI_CTRL_SPE (1 << 4)
69 unsigned long flags;
70 unsigned int timeout;
71 unsigned int ctrl;
72 int result = 0;
74 local_irq_save(flags);
76 /* Enable interrupts */
77 ctrl = asic3_read_register(a3, ASIC3_SPI_CTRL) | SPI_CTRL_SPIE;
78 asic3_write_register(a3, ASIC3_SPI_CTRL, ctrl);
80 /* Set data to send */
81 asic3_write_register(a3, ASIC3_SPI_TXDATA, data);
82 /* Start the transfer (duplex) */
83 asic3_write_register(a3, ASIC3_SPI_CTRL, (ctrl | SPI_CTRL_SPE));
85 /* Wait for transfer completion and receive data being ready */
86 for (timeout = 255; timeout > 0; timeout--) {
87 if (!(asic3_read_register(a3, ASIC3_SPI_CTRL) & SPI_CTRL_SPE)){
88 udelay(20); /* wait for a while, or we'll miss it */
89 result = asic3_read_register(a3, ASIC3_SPI_RXDATA);
90 break;
94 /* Disable interrupts */
95 ctrl = asic3_read_register(a3, ASIC3_SPI_CTRL) & ~SPI_CTRL_SPIE;
96 asic3_write_register(a3, ASIC3_SPI_CTRL, ctrl);
98 local_irq_restore(flags);
99 return result & 0xff;
102 void kbd_task(unsigned long na)
104 #define FNC_PRESS (1<<0)
105 #define FNC_REL (1<<1)
106 #define KEY_REL (1<<2)
107 #define FAKE_SHIFT (1<<3)
108 static int pressed;
109 unsigned char scancode = 0;
110 static unsigned char flags = 0;
112 scancode = asic3_spi_process_byte(0);
113 pressed = (scancode & 0x80) ? 0 : 1;
114 scancode &= ~0x80;
116 if ((scancode != KEY_FUNC) && (flags & FNC_PRESS)) {
117 if (!pressed) {
118 if (flags & FNC_REL)
119 flags &= ~(FNC_PRESS | FNC_REL | KEY_REL);
120 else
121 flags |= KEY_REL;
123 scancode += 0x40; // the keys alternate function
126 switch (scancode) {
127 case KEY_FUNC:
128 if (pressed)
129 flags = FNC_PRESS;
130 else if (flags & KEY_REL)
131 flags &= ~(FNC_PRESS | FNC_REL | KEY_REL);
132 else
133 flags |= FNC_REL;
134 break;
136 case 0x2e:case 0x37:case 0x50:case 0x52:case 0x53:case 0x5a: case 0x5b:
137 case 0x62:case 0x63:case 0x64:case 0x6b:case 0x6f:case 0x77: case 0x7c:
138 flags |= FAKE_SHIFT;
139 input_report_key(h4300_kbd, KEY_LEFTSHIFT, pressed);
140 break;
142 default:
143 if (flags & FAKE_SHIFT) {
144 input_report_key(h4300_kbd, KEY_LEFTSHIFT, 0);
145 flags &= ~FAKE_SHIFT;
147 break;
150 input_report_key(h4300_kbd, h4300_keycode[scancode], pressed);
151 input_sync(h4300_kbd);
153 DECLARE_TASKLET(task, kbd_task, 0);
155 static irqreturn_t h4300_keyboard(int irq, void *dev_id, struct pt_regs *regs)
157 tasklet_schedule(&task);
158 return IRQ_HANDLED;
161 static irqreturn_t h4300_rec_btn(int irq, void *data, struct pt_regs *regs)
163 int pressed;
164 pressed = !(asic3_get_gpio_status_d(a3) & GPIOD_RECORD_BUTTON_N);
166 printk("%s: pressed = %d\n", __FUNCTION__, pressed);
168 if (pressed)
169 set_irq_type(irq, IRQT_RISING);
170 else
171 set_irq_type(irq, IRQT_FALLING);
173 input_report_key(h4300_kbd, _KEY_RECORD, pressed);
174 input_sync(h4300_kbd);
176 return IRQ_HANDLED;
179 static irqreturn_t h4300_pwr_btn(int irq, void* data, struct pt_regs *regs)
181 int pressed;
182 pressed = !GET_H4000_GPIO(POWER_BUTTON_N);
184 input_report_key(h4300_kbd, _KEY_POWER, pressed);
185 input_sync(h4300_kbd);
187 return IRQ_HANDLED;
190 static void setup_h4300kbd(void)
192 asic3_set_clock_cdex(a3, CLOCK_CDEX_SPI, CLOCK_CDEX_SPI);
193 asic3_set_clock_cdex(a3, CLOCK_CDEX_EX1, CLOCK_CDEX_EX1);
194 udelay(20);
196 asic3_set_gpio_dir_b(a3, GPIOB_KEYBOARD_IRQ, 0);
197 asic3_set_gpio_out_b(a3,
198 (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP),
199 (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP) );
201 asic3_set_gpio_dir_c(a3, GPIOC_KEY_RXD, 0);
203 asic3_set_gpio_alt_fn_c(a3,
204 GPIOC_KEY_RXD | GPIOC_KEY_TXD | GPIOC_KEY_CLK,
205 GPIOC_KEY_RXD | GPIOC_KEY_TXD | GPIOC_KEY_CLK);
207 asic3_set_gpio_dir_d(a3, // disable h4100 buttons
208 (GPIOD_TASK_BUTTON_N | GPIOD_MAIL_BUTTON_N |
209 GPIOD_CONTACTS_BUTTON_N | GPIOD_CALENDAR_BUTTON_N),
210 (GPIOD_TASK_BUTTON_N | GPIOD_MAIL_BUTTON_N |
211 GPIOD_CONTACTS_BUTTON_N | GPIOD_CALENDAR_BUTTON_N));
212 asic3_write_register(a3, 0x400, 0xa104);
215 static int __init h4300_kbd_probe(struct platform_device * pdev)
217 int i, base_irq = asic3_irq_base(a3);
219 if (!h4000_machine_is_h4300())
220 return -ENODEV;
222 if (!(h4300_kbd = input_allocate_device()))
223 return -ENOMEM;
225 setup_h4300kbd();
227 h4300_kbd->name = "HP iPAQ h4300 keyboard driver";
228 h4300_kbd->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
229 h4300_kbd->keycode = h4300_keycode;
230 h4300_kbd->keycodesize = sizeof(unsigned char);
231 h4300_kbd->keycodemax = ARRAY_SIZE(h4300_keycode);
233 for (i = 0; i < h4300_kbd->keycodemax; i++)
234 if (h4300_keycode[i])
235 set_bit(h4300_keycode[i], h4300_kbd->keybit);
236 request_irq(base_irq + H4000_KEYBOARD_IRQ, &h4300_keyboard,
237 SA_SAMPLE_RANDOM, "Keyboard", NULL);
240 set_bit(_KEY_RECORD, h4300_kbd->keybit);
241 request_irq(base_irq + H4000_RECORD_BTN_IRQ, h4300_rec_btn,
242 SA_SAMPLE_RANDOM, "Record button", NULL);
243 set_irq_type(base_irq + H4000_RECORD_BTN_IRQ, IRQT_FALLING);
245 set_bit(_KEY_POWER, h4300_kbd->keybit);
246 request_irq(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), h4300_pwr_btn,
247 SA_SAMPLE_RANDOM, "Power button", NULL);
248 set_irq_type(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), IRQT_BOTHEDGE);
250 input_register_device(h4300_kbd);
252 return 0;
255 static int h4300_kbd_remove(struct platform_device * pdev)
257 int irq_base = asic3_irq_base(a3);
259 input_unregister_device(h4300_kbd);
260 free_irq(IRQ_GPIO(GPIO_NR_H4000_POWER_BUTTON_N), NULL);
261 free_irq(irq_base + H4000_RECORD_BTN_IRQ, &h4300_rec_btn);
262 free_irq(irq_base + H4000_KEYBOARD_IRQ, &h4300_keyboard);
264 return 0;
267 void h4300_kbd_shutdown(struct platform_device * pdev)
269 asic3_set_gpio_dir_b(a3, GPIOB_KEYBOARD_IRQ, GPIOB_KEYBOARD_IRQ);
270 asic3_set_gpio_out_b(a3,
271 (GPIOB_MICRO_3V3_EN | GPIOB_KEYBOARD_WAKE_UP), 0);
272 asic3_set_gpio_dir_c(a3,GPIOC_KEY_RXD,GPIOC_KEY_RXD);
275 int h4300_kbd_suspend(struct platform_device * pdev, pm_message_t state)
277 h4300_kbd_shutdown(pdev);
278 return 0;
280 int h4300_kbd_resume(struct platform_device * pdev)
282 setup_h4300kbd();
283 return 0;
286 static struct platform_driver h4300_kbd_driver = {
287 .probe = h4300_kbd_probe,
288 .remove = h4300_kbd_remove,
289 .shutdown = h4300_kbd_shutdown,
290 #ifdef CONFIG_PM
291 .suspend = h4300_kbd_suspend,
292 .resume = h4300_kbd_resume,
293 #endif
294 .driver = {
295 .name = "h4300_kbd",
299 static int __init h4300_kbd_init(void)
301 return platform_driver_register(&h4300_kbd_driver);
304 static void __exit h4300_kbd_exit(void)
306 platform_driver_unregister(&h4300_kbd_driver);
309 module_init(h4300_kbd_init);
310 module_exit(h4300_kbd_exit);
312 MODULE_AUTHOR("Shawn Anderson");
313 MODULE_DESCRIPTION("Keyboard support for the iPAQ h43xx");
314 MODULE_LICENSE("GPL");