aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-08-02 14:52:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-08-02 14:52:39 -0400
commitfc6bdb59a501740b28ed3b616641a22c8dc5dd31 (patch)
tree00ddba349c7e96b03af0913da1a74eae8a94a2db /arch
parent44d82e2963551eafa378a3fc7a923df7853af4e2 (diff)
parent1fcfd08bd0704e1888bd73153e8d2ca3640e22f2 (diff)
Merge branch 'for-linus-3.6' of git://dev.laptop.org/users/dilinger/linux-olpc
Pull OLPC platform updates from Andres Salomon: "These move the OLPC Embedded Controller driver out of arch/x86/platform and into drivers/platform/olpc. OLPC machines are now ARM-based (which means lots of x86 and ARM changes), but are typically pretty self-contained.. so it makes more sense to go through a separate OLPC tree after getting the appropriate review/ACKs." * 'for-linus-3.6' of git://dev.laptop.org/users/dilinger/linux-olpc: x86: OLPC: move s/r-related EC cmds to EC driver Platform: OLPC: move global variables into priv struct Platform: OLPC: move debugfs support from x86 EC driver x86: OLPC: switch over to using new EC driver on x86 Platform: OLPC: add a suspended flag to the EC driver Platform: OLPC: turn EC driver into a platform_driver Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it drivers: OLPC: update various drivers to include olpc-ec.h Platform: OLPC: add a stub to drivers/platform/ for the OLPC EC driver
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/olpc.h19
-rw-r--r--arch/x86/platform/olpc/olpc-xo1-pm.c16
-rw-r--r--arch/x86/platform/olpc/olpc-xo1-sci.c1
-rw-r--r--arch/x86/platform/olpc/olpc-xo15-sci.c1
-rw-r--r--arch/x86/platform/olpc/olpc.c190
5 files changed, 65 insertions, 162 deletions
diff --git a/arch/x86/include/asm/olpc.h b/arch/x86/include/asm/olpc.h
index 87bdbca72f94..72f9adf6eca4 100644
--- a/arch/x86/include/asm/olpc.h
+++ b/arch/x86/include/asm/olpc.h
@@ -100,25 +100,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value);
100 100
101extern int pci_olpc_init(void); 101extern int pci_olpc_init(void);
102 102
103/* EC related functions */
104
105extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
106 unsigned char *outbuf, size_t outlen);
107
108/* EC commands */
109
110#define EC_FIRMWARE_REV 0x08
111#define EC_WRITE_SCI_MASK 0x1b
112#define EC_WAKE_UP_WLAN 0x24
113#define EC_WLAN_LEAVE_RESET 0x25
114#define EC_READ_EB_MODE 0x2a
115#define EC_SET_SCI_INHIBIT 0x32
116#define EC_SET_SCI_INHIBIT_RELEASE 0x34
117#define EC_WLAN_ENTER_RESET 0x35
118#define EC_WRITE_EXT_SCI_MASK 0x38
119#define EC_SCI_QUERY 0x84
120#define EC_EXT_SCI_QUERY 0x85
121
122/* SCI source values */ 103/* SCI source values */
123 104
124#define EC_SCI_SRC_EMPTY 0x00 105#define EC_SCI_SRC_EMPTY 0x00
diff --git a/arch/x86/platform/olpc/olpc-xo1-pm.c b/arch/x86/platform/olpc/olpc-xo1-pm.c
index 0ce8616c88ae..d75582d1aa55 100644
--- a/arch/x86/platform/olpc/olpc-xo1-pm.c
+++ b/arch/x86/platform/olpc/olpc-xo1-pm.c
@@ -18,6 +18,7 @@
18#include <linux/pm.h> 18#include <linux/pm.h>
19#include <linux/mfd/core.h> 19#include <linux/mfd/core.h>
20#include <linux/suspend.h> 20#include <linux/suspend.h>
21#include <linux/olpc-ec.h>
21 22
22#include <asm/io.h> 23#include <asm/io.h>
23#include <asm/olpc.h> 24#include <asm/olpc.h>
@@ -51,16 +52,11 @@ EXPORT_SYMBOL_GPL(olpc_xo1_pm_wakeup_clear);
51static int xo1_power_state_enter(suspend_state_t pm_state) 52static int xo1_power_state_enter(suspend_state_t pm_state)
52{ 53{
53 unsigned long saved_sci_mask; 54 unsigned long saved_sci_mask;
54 int r;
55 55
56 /* Only STR is supported */ 56 /* Only STR is supported */
57 if (pm_state != PM_SUSPEND_MEM) 57 if (pm_state != PM_SUSPEND_MEM)
58 return -EINVAL; 58 return -EINVAL;
59 59
60 r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
61 if (r)
62 return r;
63
64 /* 60 /*
65 * Save SCI mask (this gets lost since PM1_EN is used as a mask for 61 * Save SCI mask (this gets lost since PM1_EN is used as a mask for
66 * wakeup events, which is not necessarily the same event set) 62 * wakeup events, which is not necessarily the same event set)
@@ -76,16 +72,6 @@ static int xo1_power_state_enter(suspend_state_t pm_state)
76 /* Restore SCI mask (using dword access to CS5536_PM1_EN) */ 72 /* Restore SCI mask (using dword access to CS5536_PM1_EN) */
77 outl(saved_sci_mask, acpi_base + CS5536_PM1_STS); 73 outl(saved_sci_mask, acpi_base + CS5536_PM1_STS);
78 74
79 /* Tell the EC to stop inhibiting SCIs */
80 olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
81
82 /*
83 * Tell the wireless module to restart USB communication.
84 * Must be done twice.
85 */
86 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
87 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
88
89 return 0; 75 return 0;
90} 76}
91 77
diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c
index 04b8c73659c5..63d4aa40956e 100644
--- a/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -23,6 +23,7 @@
23#include <linux/power_supply.h> 23#include <linux/power_supply.h>
24#include <linux/suspend.h> 24#include <linux/suspend.h>
25#include <linux/workqueue.h> 25#include <linux/workqueue.h>
26#include <linux/olpc-ec.h>
26 27
27#include <asm/io.h> 28#include <asm/io.h>
28#include <asm/msr.h> 29#include <asm/msr.h>
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c
index 599be499fdf7..2fdca25905ae 100644
--- a/arch/x86/platform/olpc/olpc-xo15-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo15-sci.c
@@ -13,6 +13,7 @@
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <linux/workqueue.h> 14#include <linux/workqueue.h>
15#include <linux/power_supply.h> 15#include <linux/power_supply.h>
16#include <linux/olpc-ec.h>
16 17
17#include <acpi/acpi_bus.h> 18#include <acpi/acpi_bus.h>
18#include <acpi/acpi_drivers.h> 19#include <acpi/acpi_drivers.h>
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