aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/platform/olpc/olpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/platform/olpc/olpc.c')
-rw-r--r--arch/x86/platform/olpc/olpc.c190
1 files changed, 62 insertions, 128 deletions
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index a4bee53c2e54..27376081ddec 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -14,14 +14,13 @@
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/module.h> 15#include <linux/module.h>
16#include <linux/delay.h> 16#include <linux/delay.h>
17#include <linux/spinlock.h>
18#include <linux/io.h> 17#include <linux/io.h>
19#include <linux/string.h> 18#include <linux/string.h>
20#include <linux/platform_device.h> 19#include <linux/platform_device.h>
21#include <linux/of.h> 20#include <linux/of.h>
22#include <linux/syscore_ops.h> 21#include <linux/syscore_ops.h>
23#include <linux/debugfs.h>
24#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/olpc-ec.h>
25 24
26#include <asm/geode.h> 25#include <asm/geode.h>
27#include <asm/setup.h> 26#include <asm/setup.h>
@@ -31,17 +30,6 @@
31struct olpc_platform_t olpc_platform_info; 30struct olpc_platform_t olpc_platform_info;
32EXPORT_SYMBOL_GPL(olpc_platform_info); 31EXPORT_SYMBOL_GPL(olpc_platform_info);
33 32
34static DEFINE_SPINLOCK(ec_lock);
35
36/* debugfs interface to EC commands */
37#define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */
38#define EC_MAX_CMD_REPLY (8)
39
40static struct dentry *ec_debugfs_dir;
41static DEFINE_MUTEX(ec_debugfs_cmd_lock);
42static unsigned char ec_debugfs_resp[EC_MAX_CMD_REPLY];
43static unsigned int ec_debugfs_resp_bytes;
44
45/* EC event mask to be applied during suspend (defining wakeup sources). */ 33/* EC event mask to be applied during suspend (defining wakeup sources). */
46static u16 ec_wakeup_mask; 34static u16 ec_wakeup_mask;
47 35
@@ -125,16 +113,13 @@ static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
125 * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while 113 * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while
126 * OpenFirmware's source is available, the EC's is not. 114 * OpenFirmware's source is available, the EC's is not.
127 */ 115 */
128int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, 116static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
129 unsigned char *outbuf, size_t outlen) 117 size_t outlen, void *arg)
130{ 118{
131 unsigned long flags;
132 int ret = -EIO; 119 int ret = -EIO;
133 int i; 120 int i;
134 int restarts = 0; 121 int restarts = 0;
135 122
136 spin_lock_irqsave(&ec_lock, flags);
137
138 /* Clear OBF */ 123 /* Clear OBF */
139 for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++) 124 for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
140 inb(0x68); 125 inb(0x68);
@@ -198,10 +183,8 @@ restart:
198 183
199 ret = 0; 184 ret = 0;
200err: 185err:
201 spin_unlock_irqrestore(&ec_lock, flags);
202 return ret; 186 return ret;
203} 187}
204EXPORT_SYMBOL_GPL(olpc_ec_cmd);
205 188
206void olpc_ec_wakeup_set(u16 value) 189void olpc_ec_wakeup_set(u16 value)
207{ 190{
@@ -280,96 +263,6 @@ int olpc_ec_sci_query(u16 *sci_value)
280} 263}
281EXPORT_SYMBOL_GPL(olpc_ec_sci_query); 264EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
282 265
283static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf,
284 size_t size, loff_t *ppos)
285{
286 int i, m;
287 unsigned char ec_cmd[EC_MAX_CMD_ARGS];
288 unsigned int ec_cmd_int[EC_MAX_CMD_ARGS];
289 char cmdbuf[64];
290 int ec_cmd_bytes;
291
292 mutex_lock(&ec_debugfs_cmd_lock);
293
294 size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size);
295
296 m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0],
297 &ec_debugfs_resp_bytes,
298 &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3],
299 &ec_cmd_int[4], &ec_cmd_int[5]);
300 if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) {
301 /* reset to prevent overflow on read */
302 ec_debugfs_resp_bytes = 0;
303
304 printk(KERN_DEBUG "olpc-ec: bad ec cmd: "
305 "cmd:response-count [arg1 [arg2 ...]]\n");
306 size = -EINVAL;
307 goto out;
308 }
309
310 /* convert scanf'd ints to char */
311 ec_cmd_bytes = m - 2;
312 for (i = 0; i <= ec_cmd_bytes; i++)
313 ec_cmd[i] = ec_cmd_int[i];
314
315 printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args "
316 "%02x %02x %02x %02x %02x, want %d returns\n",
317 ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3],
318 ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes);
319
320 olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
321 ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes);
322
323 printk(KERN_DEBUG "olpc-ec: response "
324 "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n",
325 ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2],
326 ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5],
327 ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes);
328
329out:
330 mutex_unlock(&ec_debugfs_cmd_lock);
331 return size;
332}
333
334static ssize_t ec_debugfs_cmd_read(struct file *file, char __user *buf,
335 size_t size, loff_t *ppos)
336{
337 unsigned int i, r;
338 char *rp;
339 char respbuf[64];
340
341 mutex_lock(&ec_debugfs_cmd_lock);
342 rp = respbuf;
343 rp += sprintf(rp, "%02x", ec_debugfs_resp[0]);
344 for (i = 1; i < ec_debugfs_resp_bytes; i++)
345 rp += sprintf(rp, ", %02x", ec_debugfs_resp[i]);
346 mutex_unlock(&ec_debugfs_cmd_lock);
347 rp += sprintf(rp, "\n");
348
349 r = rp - respbuf;
350 return simple_read_from_buffer(buf, size, ppos, respbuf, r);
351}
352
353static const struct file_operations ec_debugfs_genops = {
354 .write = ec_debugfs_cmd_write,
355 .read = ec_debugfs_cmd_read,
356};
357
358static void setup_debugfs(void)
359{
360 ec_debugfs_dir = debugfs_create_dir("olpc-ec", 0);
361 if (ec_debugfs_dir == ERR_PTR(-ENODEV))
362 return;
363
364 debugfs_create_file("cmd", 0600, ec_debugfs_dir, NULL,
365 &ec_debugfs_genops);
366}
367
368static int olpc_ec_suspend(void)
369{
370 return olpc_ec_mask_write(ec_wakeup_mask);
371}
372
373static bool __init check_ofw_architecture(struct device_node *root) 266static bool __init check_ofw_architecture(struct device_node *root)
374{ 267{
375 const char *olpc_arch; 268 const char *olpc_arch;
@@ -424,8 +317,59 @@ static int __init add_xo1_platform_devices(void)
424 return 0; 317 return 0;
425} 318}
426 319
427static struct syscore_ops olpc_syscore_ops = { 320static int olpc_xo1_ec_probe(struct platform_device *pdev)
428 .suspend = olpc_ec_suspend, 321{
322 /* get the EC revision */
323 olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
324 (unsigned char *) &olpc_platform_info.ecver, 1);
325
326 /* EC version 0x5f adds support for wide SCI mask */
327 if (olpc_platform_info.ecver >= 0x5f)
328 olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;
329
330 pr_info("OLPC board revision %s%X (EC=%x)\n",
331 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
332 olpc_platform_info.boardrev >> 4,
333 olpc_platform_info.ecver);
334
335 return 0;
336}
337static int olpc_xo1_ec_suspend(struct platform_device *pdev)
338{
339 olpc_ec_mask_write(ec_wakeup_mask);
340
341 /*
342 * Squelch SCIs while suspended. This is a fix for
343 * <http://dev.laptop.org/ticket/1835>.
344 */
345 return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
346}
347
348static int olpc_xo1_ec_resume(struct platform_device *pdev)
349{
350 /* Tell the EC to stop inhibiting SCIs */
351 olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
352
353 /*
354 * Tell the wireless module to restart USB communication.
355 * Must be done twice.
356 */
357 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
358 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
359
360 return 0;
361}
362
363static struct olpc_ec_driver ec_xo1_driver = {
364 .probe = olpc_xo1_ec_probe,
365 .suspend = olpc_xo1_ec_suspend,
366 .resume = olpc_xo1_ec_resume,
367 .ec_cmd = olpc_xo1_ec_cmd,
368};
369
370static struct olpc_ec_driver ec_xo1_5_driver = {
371 .probe = olpc_xo1_ec_probe,
372 .ec_cmd = olpc_xo1_ec_cmd,
429}; 373};
430 374
431static int __init olpc_init(void) 375static int __init olpc_init(void)
@@ -435,16 +379,17 @@ static int __init olpc_init(void)
435 if (!olpc_ofw_present() || !platform_detect()) 379 if (!olpc_ofw_present() || !platform_detect())
436 return 0; 380 return 0;
437 381
438 spin_lock_init(&ec_lock); 382 /* register the XO-1 and 1.5-specific EC handler */
383 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
384 olpc_ec_driver_register(&ec_xo1_driver, NULL);
385 else
386 olpc_ec_driver_register(&ec_xo1_5_driver, NULL);
387 platform_device_register_simple("olpc-ec", -1, NULL, 0);
439 388
440 /* assume B1 and above models always have a DCON */ 389 /* assume B1 and above models always have a DCON */
441 if (olpc_board_at_least(olpc_board(0xb1))) 390 if (olpc_board_at_least(olpc_board(0xb1)))
442 olpc_platform_info.flags |= OLPC_F_DCON; 391 olpc_platform_info.flags |= OLPC_F_DCON;
443 392
444 /* get the EC revision */
445 olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
446 (unsigned char *) &olpc_platform_info.ecver, 1);
447
448#ifdef CONFIG_PCI_OLPC 393#ifdef CONFIG_PCI_OLPC
449 /* If the VSA exists let it emulate PCI, if not emulate in kernel. 394 /* If the VSA exists let it emulate PCI, if not emulate in kernel.
450 * XO-1 only. */ 395 * XO-1 only. */
@@ -452,14 +397,6 @@ static int __init olpc_init(void)
452 !cs5535_has_vsa2()) 397 !cs5535_has_vsa2())
453 x86_init.pci.arch_init = pci_olpc_init; 398 x86_init.pci.arch_init = pci_olpc_init;
454#endif 399#endif
455 /* EC version 0x5f adds support for wide SCI mask */
456 if (olpc_platform_info.ecver >= 0x5f)
457 olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;
458
459 printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
460 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
461 olpc_platform_info.boardrev >> 4,
462 olpc_platform_info.ecver);
463 400
464 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */ 401 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
465 r = add_xo1_platform_devices(); 402 r = add_xo1_platform_devices();
@@ -467,9 +404,6 @@ static int __init olpc_init(void)
467 return r; 404 return r;
468 } 405 }
469 406
470 register_syscore_ops(&olpc_syscore_ops);
471 setup_debugfs();
472
473 return 0; 407 return 0;
474} 408}
475 409