]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/input/misc/apanel.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[karo-tx-linux.git] / drivers / input / misc / apanel.c
1 /*
2  *  Fujitsu Lifebook Application Panel button drive
3  *
4  *  Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
5  *  Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org>
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  * Many Fujitsu Lifebook laptops have a small panel of buttons that are
12  * accessible via the i2c/smbus interface. This driver polls those
13  * buttons and generates input events.
14  *
15  * For more details see:
16  *      http://apanel.sourceforge.net/tech.php
17  */
18
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/ioport.h>
22 #include <linux/io.h>
23 #include <linux/input-polldev.h>
24 #include <linux/i2c.h>
25 #include <linux/workqueue.h>
26 #include <linux/leds.h>
27
28 #define APANEL_NAME     "Fujitsu Application Panel"
29 #define APANEL_VERSION  "1.3.1"
30 #define APANEL          "apanel"
31
32 /* How often we poll keys - msecs */
33 #define POLL_INTERVAL_DEFAULT   1000
34
35 /* Magic constants in BIOS that tell about buttons */
36 enum apanel_devid {
37         APANEL_DEV_NONE   = 0,
38         APANEL_DEV_APPBTN = 1,
39         APANEL_DEV_CDBTN  = 2,
40         APANEL_DEV_LCD    = 3,
41         APANEL_DEV_LED    = 4,
42
43         APANEL_DEV_MAX,
44 };
45
46 enum apanel_chip {
47         CHIP_NONE    = 0,
48         CHIP_OZ992C  = 1,
49         CHIP_OZ163T  = 2,
50         CHIP_OZ711M3 = 4,
51 };
52
53 /* Result of BIOS snooping/probing -- what features are supported */
54 static enum apanel_chip device_chip[APANEL_DEV_MAX];
55
56 #define MAX_PANEL_KEYS  12
57
58 struct apanel {
59         struct input_polled_dev *ipdev;
60         struct i2c_client *client;
61         unsigned short keymap[MAX_PANEL_KEYS];
62         u16    nkeys;
63         u16    led_bits;
64         struct work_struct led_work;
65         struct led_classdev mail_led;
66 };
67
68
69 static int apanel_probe(struct i2c_client *, const struct i2c_device_id *);
70
71 static void report_key(struct input_dev *input, unsigned keycode)
72 {
73         pr_debug(APANEL ": report key %#x\n", keycode);
74         input_report_key(input, keycode, 1);
75         input_sync(input);
76
77         input_report_key(input, keycode, 0);
78         input_sync(input);
79 }
80
81 /* Poll for key changes
82  *
83  * Read Application keys via SMI
84  *  A (0x4), B (0x8), Internet (0x2), Email (0x1).
85  *
86  * CD keys:
87  * Forward (0x100), Rewind (0x200), Stop (0x400), Pause (0x800)
88  */
89 static void apanel_poll(struct input_polled_dev *ipdev)
90 {
91         struct apanel *ap = ipdev->private;
92         struct input_dev *idev = ipdev->input;
93         u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
94         s32 data;
95         int i;
96
97         data = i2c_smbus_read_word_data(ap->client, cmd);
98         if (data < 0)
99                 return; /* ignore errors (due to ACPI??) */
100
101         /* write back to clear latch */
102         i2c_smbus_write_word_data(ap->client, cmd, 0);
103
104         if (!data)
105                 return;
106
107         dev_dbg(&idev->dev, APANEL ": data %#x\n", data);
108         for (i = 0; i < idev->keycodemax; i++)
109                 if ((1u << i) & data)
110                         report_key(idev, ap->keymap[i]);
111 }
112
113 /* Track state changes of LED */
114 static void led_update(struct work_struct *work)
115 {
116         struct apanel *ap = container_of(work, struct apanel, led_work);
117
118         i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits);
119 }
120
121 static void mail_led_set(struct led_classdev *led,
122                          enum led_brightness value)
123 {
124         struct apanel *ap = container_of(led, struct apanel, mail_led);
125
126         if (value != LED_OFF)
127                 ap->led_bits |= 0x8000;
128         else
129                 ap->led_bits &= ~0x8000;
130
131         schedule_work(&ap->led_work);
132 }
133
134 static int apanel_remove(struct i2c_client *client)
135 {
136         struct apanel *ap = i2c_get_clientdata(client);
137
138         if (device_chip[APANEL_DEV_LED] != CHIP_NONE)
139                 led_classdev_unregister(&ap->mail_led);
140
141         input_unregister_polled_device(ap->ipdev);
142         input_free_polled_device(ap->ipdev);
143
144         return 0;
145 }
146
147 static void apanel_shutdown(struct i2c_client *client)
148 {
149         apanel_remove(client);
150 }
151
152 static const struct i2c_device_id apanel_id[] = {
153         { "fujitsu_apanel", 0 },
154         { }
155 };
156 MODULE_DEVICE_TABLE(i2c, apanel_id);
157
158 static struct i2c_driver apanel_driver = {
159         .driver = {
160                 .name = APANEL,
161         },
162         .probe          = &apanel_probe,
163         .remove         = &apanel_remove,
164         .shutdown       = &apanel_shutdown,
165         .id_table       = apanel_id,
166 };
167
168 static struct apanel apanel = {
169         .keymap = {
170                 [0] = KEY_MAIL,
171                 [1] = KEY_WWW,
172                 [2] = KEY_PROG2,
173                 [3] = KEY_PROG1,
174
175                 [8] = KEY_FORWARD,
176                 [9] = KEY_REWIND,
177                 [10] = KEY_STOPCD,
178                 [11] = KEY_PLAYPAUSE,
179
180         },
181         .mail_led = {
182                 .name = "mail:blue",
183                 .brightness_set = mail_led_set,
184         },
185 };
186
187 /* NB: Only one panel on the i2c. */
188 static int apanel_probe(struct i2c_client *client,
189                         const struct i2c_device_id *id)
190 {
191         struct apanel *ap;
192         struct input_polled_dev *ipdev;
193         struct input_dev *idev;
194         u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
195         int i, err = -ENOMEM;
196
197         ap = &apanel;
198
199         ipdev = input_allocate_polled_device();
200         if (!ipdev)
201                 goto out1;
202
203         ap->ipdev = ipdev;
204         ap->client = client;
205
206         i2c_set_clientdata(client, ap);
207
208         err = i2c_smbus_write_word_data(client, cmd, 0);
209         if (err) {
210                 dev_warn(&client->dev, APANEL ": smbus write error %d\n",
211                          err);
212                 goto out3;
213         }
214
215         ipdev->poll = apanel_poll;
216         ipdev->poll_interval = POLL_INTERVAL_DEFAULT;
217         ipdev->private = ap;
218
219         idev = ipdev->input;
220         idev->name = APANEL_NAME " buttons";
221         idev->phys = "apanel/input0";
222         idev->id.bustype = BUS_HOST;
223         idev->dev.parent = &client->dev;
224
225         set_bit(EV_KEY, idev->evbit);
226
227         idev->keycode = ap->keymap;
228         idev->keycodesize = sizeof(ap->keymap[0]);
229         idev->keycodemax = (device_chip[APANEL_DEV_CDBTN] != CHIP_NONE) ? 12 : 4;
230
231         for (i = 0; i < idev->keycodemax; i++)
232                 if (ap->keymap[i])
233                         set_bit(ap->keymap[i], idev->keybit);
234
235         err = input_register_polled_device(ipdev);
236         if (err)
237                 goto out3;
238
239         INIT_WORK(&ap->led_work, led_update);
240         if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
241                 err = led_classdev_register(&client->dev, &ap->mail_led);
242                 if (err)
243                         goto out4;
244         }
245
246         return 0;
247 out4:
248         input_unregister_polled_device(ipdev);
249 out3:
250         input_free_polled_device(ipdev);
251 out1:
252         return err;
253 }
254
255 /* Scan the system ROM for the signature "FJKEYINF" */
256 static __init const void __iomem *bios_signature(const void __iomem *bios)
257 {
258         ssize_t offset;
259         const unsigned char signature[] = "FJKEYINF";
260
261         for (offset = 0; offset < 0x10000; offset += 0x10) {
262                 if (check_signature(bios + offset, signature,
263                                     sizeof(signature)-1))
264                         return bios + offset;
265         }
266         pr_notice(APANEL ": Fujitsu BIOS signature '%s' not found...\n",
267                   signature);
268         return NULL;
269 }
270
271 static int __init apanel_init(void)
272 {
273         void __iomem *bios;
274         const void __iomem *p;
275         u8 devno;
276         unsigned char i2c_addr;
277         int found = 0;
278
279         bios = ioremap(0xF0000, 0x10000); /* Can't fail */
280
281         p = bios_signature(bios);
282         if (!p) {
283                 iounmap(bios);
284                 return -ENODEV;
285         }
286
287         /* just use the first address */
288         p += 8;
289         i2c_addr = readb(p + 3) >> 1;
290
291         for ( ; (devno = readb(p)) & 0x7f; p += 4) {
292                 unsigned char method, slave, chip;
293
294                 method = readb(p + 1);
295                 chip = readb(p + 2);
296                 slave = readb(p + 3) >> 1;
297
298                 if (slave != i2c_addr) {
299                         pr_notice(APANEL ": only one SMBus slave "
300                                   "address supported, skiping device...\n");
301                         continue;
302                 }
303
304                 /* translate alternative device numbers */
305                 switch (devno) {
306                 case 6:
307                         devno = APANEL_DEV_APPBTN;
308                         break;
309                 case 7:
310                         devno = APANEL_DEV_LED;
311                         break;
312                 }
313
314                 if (devno >= APANEL_DEV_MAX)
315                         pr_notice(APANEL ": unknown device %u found\n", devno);
316                 else if (device_chip[devno] != CHIP_NONE)
317                         pr_warning(APANEL ": duplicate entry for devno %u\n", devno);
318
319                 else if (method != 1 && method != 2 && method != 4) {
320                         pr_notice(APANEL ": unknown method %u for devno %u\n",
321                                   method, devno);
322                 } else {
323                         device_chip[devno] = (enum apanel_chip) chip;
324                         ++found;
325                 }
326         }
327         iounmap(bios);
328
329         if (found == 0) {
330                 pr_info(APANEL ": no input devices reported by BIOS\n");
331                 return -EIO;
332         }
333
334         return i2c_add_driver(&apanel_driver);
335 }
336 module_init(apanel_init);
337
338 static void __exit apanel_cleanup(void)
339 {
340         i2c_del_driver(&apanel_driver);
341 }
342 module_exit(apanel_cleanup);
343
344 MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
345 MODULE_DESCRIPTION(APANEL_NAME " driver");
346 MODULE_LICENSE("GPL");
347 MODULE_VERSION(APANEL_VERSION);
348
349 MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*");
350 MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*");