2 * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * You should have received a copy of the GNU General Public License along
9 * with this program; if not, write to the Free Software Foundation, Inc.,
10 * 675 Mass Ave, Cambridge, MA 02139, USA.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/i2c.h>
17 #include <linux/input.h>
18 #include <linux/irq.h>
19 #include <linux/interrupt.h>
21 #include <linux/workqueue.h>
23 #include <asm/mach-jz4740/irq.h>
24 #include <asm/mach-jz4740/gpio.h>
27 struct i2c_client
*client
;
28 struct input_dev
*input
;
30 struct work_struct work
;
33 static const unsigned int n526_lpc_keymap
[] = {
35 [0x02] = KEY_PAGEDOWN
,
36 [0x03] = KEY_VOLUMEUP
,
37 [0x04] = KEY_VOLUMEDOWN
,
42 [0x0a] = KEY_LEFTSHIFT
,
52 [0x14] = KEY_DOCUMENTS
,
72 /* [0x28] = KEY_SYM, */
85 [0x35] = KEY_BACKSPACE
,
90 static void n526_lpc_irq_work(struct work_struct
*work
)
93 struct n526_lpc
*n526_lpc
= container_of(work
, struct n526_lpc
, work
);
94 struct i2c_client
*client
= n526_lpc
->client
;
95 unsigned char raw_msg
;
96 struct i2c_msg msg
= {client
->addr
, client
->flags
| I2C_M_RD
, 1, &raw_msg
};
97 unsigned char keycode
;
100 ret
= i2c_transfer(client
->adapter
, &msg
, 1);
103 dev_err(&client
->dev
, "Failed to read lpc status\n");
106 keycode
= raw_msg
& 0x7f;
108 if (keycode
< ARRAY_SIZE(n526_lpc_keymap
)) {
109 input_report_key(n526_lpc
->input
, n526_lpc_keymap
[keycode
],
111 input_sync(n526_lpc
->input
);
115 static irqreturn_t
n526_lpc_irq(int irq
, void *dev_id
)
117 struct n526_lpc
*n526_lpc
= dev_id
;
119 schedule_work(&n526_lpc
->work
);
123 static int __devinit
n526_lpc_probe(struct i2c_client
*client
,
124 const struct i2c_device_id
*id
)
128 struct n526_lpc
*n526_lpc
;
129 struct input_dev
*input
;
131 n526_lpc
= kmalloc(sizeof(*n526_lpc
), GFP_KERNEL
);
134 dev_err(&client
->dev
, "Failed to allocate device structure\n");
138 input
= input_allocate_device();
140 dev_err(&client
->dev
, "Failed to allocate input device\n");
145 input
->name
= "n526-keys";
146 input
->phys
= "n526-keys/input0";
147 input
->dev
.parent
= &client
->dev
;
148 input
->id
.bustype
= BUS_I2C
;
149 input
->id
.vendor
= 0x0001;
150 input
->id
.product
= 0x0001;
151 input
->id
.version
= 0x0001;
153 __set_bit(EV_KEY
, input
->evbit
);
155 for (i
= 0; i
< ARRAY_SIZE(n526_lpc_keymap
); ++i
) {
156 if (n526_lpc_keymap
[i
] != 0)
157 __set_bit(n526_lpc_keymap
[i
], input
->keybit
);
160 ret
= input_register_device(input
);
163 dev_err(&client
->dev
, "Failed to register input device: %d\n", ret
);
167 n526_lpc
->client
= client
;
168 n526_lpc
->input
= input
;
169 INIT_WORK(&n526_lpc
->work
, n526_lpc_irq_work
);
171 ret
= request_irq(client
->irq
, n526_lpc_irq
, IRQF_TRIGGER_FALLING
,
172 "n526-lpc", n526_lpc
);
174 dev_err(&client
->dev
, "Failed to request irq: %d\n", ret
);
175 goto err_unregister_input
;
178 i2c_set_clientdata(client
, n526_lpc
);
182 err_unregister_input
:
183 input_unregister_device(input
);
185 input_free_device(input
);
192 static int n526_lpc_remove(struct i2c_client
*client
)
194 struct n526_lpc
*n526_lpc
= i2c_get_clientdata(client
);
196 free_irq(client
->irq
, n526_lpc
);
198 i2c_set_clientdata(client
, NULL
);
199 input_unregister_device(n526_lpc
->input
);
200 input_free_device(n526_lpc
->input
);
206 static const struct i2c_device_id n526_lpc_id
[] = {
210 MODULE_DEVICE_TABLE(i2c
, n526_lpc_id
);
212 static struct i2c_driver n526_lpc_driver
= {
215 .owner
= THIS_MODULE
,
217 .probe
= n526_lpc_probe
,
218 .remove
= n526_lpc_remove
,
219 .id_table
= n526_lpc_id
,
222 static int __init
n526_lpc_init(void)
224 return i2c_add_driver(&n526_lpc_driver
);
226 module_init(n526_lpc_init
);
228 static void __exit
n526_lpc_exit(void)
230 i2c_del_driver(&n526_lpc_driver
);
232 module_exit(n526_lpc_exit
);
234 MODULE_LICENSE("GPL");
235 MODULE_AUTHOR("Lars-Peter Clausen");
236 MODULE_DESCRIPTION("n526 keypad driver");
237 MODULE_ALIAS("i2c:n526-keys");