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