Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86, olpc: EC SCI wakeup mask functionality

Update the EC SCI masks with recent additions.

Add functions to query SCI events and set the wakeup mask, to be used by
followup patches.

Add functions to tweak an event mask used to select certain EC events as
a system wakeup source. Also add a function to determine if EC wakeup
functionality is available, as this depends on child drivers (different
for each laptop model) to configure the SCI interrupt.

Signed-off-by: Daniel Drake <dsd@laptop.org>
Link: http://lkml.kernel.org/r/1309019658-1712-7-git-send-email-dsd@laptop.org
Acked-by: Andres Salomon <dilinger@queued.net>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

authored by

Daniel Drake and committed by
H. Peter Anvin
bc4ecd5a 7feda8e9

+111 -6
+25 -6
arch/x86/include/asm/olpc.h
··· 13 13 14 14 #define OLPC_F_PRESENT 0x01 15 15 #define OLPC_F_DCON 0x02 16 + #define OLPC_F_EC_WIDE_SCI 0x04 16 17 17 18 #ifdef CONFIG_OLPC 18 19 ··· 63 62 return olpc_platform_info.boardrev >= rev; 64 63 } 65 64 65 + extern void olpc_ec_wakeup_set(u16 value); 66 + extern void olpc_ec_wakeup_clear(u16 value); 67 + extern bool olpc_ec_wakeup_available(void); 68 + 69 + extern int olpc_ec_mask_write(u16 bits); 70 + extern int olpc_ec_sci_query(u16 *sci_value); 71 + 66 72 #else 67 73 68 74 static inline int machine_is_olpc(void) ··· 80 72 static inline int olpc_has_dcon(void) 81 73 { 82 74 return 0; 75 + } 76 + 77 + static inline void olpc_ec_wakeup_set(u16 value) { } 78 + static inline void olpc_ec_wakeup_clear(u16 value) { } 79 + 80 + static inline bool olpc_ec_wakeup_available(void) 81 + { 82 + return false; 83 83 } 84 84 85 85 #endif ··· 105 89 extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen, 106 90 unsigned char *outbuf, size_t outlen); 107 91 108 - extern int olpc_ec_mask_set(uint8_t bits); 109 - extern int olpc_ec_mask_unset(uint8_t bits); 110 - 111 92 /* EC commands */ 112 93 113 94 #define EC_FIRMWARE_REV 0x08 95 + #define EC_WRITE_SCI_MASK 0x1b 114 96 #define EC_WAKE_UP_WLAN 0x24 115 97 #define EC_WLAN_LEAVE_RESET 0x25 116 98 #define EC_SET_SCI_INHIBIT 0x32 117 99 #define EC_SET_SCI_INHIBIT_RELEASE 0x34 118 100 #define EC_WLAN_ENTER_RESET 0x35 101 + #define EC_WRITE_EXT_SCI_MASK 0x38 102 + #define EC_SCI_QUERY 0x84 103 + #define EC_EXT_SCI_QUERY 0x85 119 104 120 105 /* SCI source values */ 121 106 ··· 125 108 #define EC_SCI_SRC_BATTERY 0x02 126 109 #define EC_SCI_SRC_BATSOC 0x04 127 110 #define EC_SCI_SRC_BATERR 0x08 128 - #define EC_SCI_SRC_EBOOK 0x10 129 - #define EC_SCI_SRC_WLAN 0x20 111 + #define EC_SCI_SRC_EBOOK 0x10 /* XO-1 only */ 112 + #define EC_SCI_SRC_WLAN 0x20 /* XO-1 only */ 130 113 #define EC_SCI_SRC_ACPWR 0x40 131 - #define EC_SCI_SRC_ALL 0x7F 114 + #define EC_SCI_SRC_BATCRIT 0x80 115 + #define EC_SCI_SRC_GPWAKE 0x100 /* XO-1.5 only */ 116 + #define EC_SCI_SRC_ALL 0x1FF 132 117 133 118 /* GPIO assignments */ 134 119
+86
arch/x86/platform/olpc/olpc.c
··· 19 19 #include <linux/string.h> 20 20 #include <linux/platform_device.h> 21 21 #include <linux/of.h> 22 + #include <linux/syscore_ops.h> 22 23 23 24 #include <asm/geode.h> 24 25 #include <asm/setup.h> ··· 30 29 EXPORT_SYMBOL_GPL(olpc_platform_info); 31 30 32 31 static DEFINE_SPINLOCK(ec_lock); 32 + 33 + /* EC event mask to be applied during suspend (defining wakeup sources). */ 34 + static u16 ec_wakeup_mask; 33 35 34 36 /* what the timeout *should* be (in ms) */ 35 37 #define EC_BASE_TIMEOUT 20 ··· 192 188 } 193 189 EXPORT_SYMBOL_GPL(olpc_ec_cmd); 194 190 191 + void olpc_ec_wakeup_set(u16 value) 192 + { 193 + ec_wakeup_mask |= value; 194 + } 195 + EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set); 196 + 197 + void olpc_ec_wakeup_clear(u16 value) 198 + { 199 + ec_wakeup_mask &= ~value; 200 + } 201 + EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear); 202 + 203 + /* 204 + * Returns true if the compile and runtime configurations allow for EC events 205 + * to wake the system. 206 + */ 207 + bool olpc_ec_wakeup_available(void) 208 + { 209 + if (!machine_is_olpc()) 210 + return false; 211 + 212 + /* 213 + * XO-1 EC wakeups are available when olpc-xo1-sci driver is 214 + * compiled in 215 + */ 216 + #ifdef CONFIG_OLPC_XO1_SCI 217 + if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */ 218 + return true; 219 + #endif 220 + 221 + return false; 222 + } 223 + EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available); 224 + 225 + int olpc_ec_mask_write(u16 bits) 226 + { 227 + if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) { 228 + __be16 ec_word = cpu_to_be16(bits); 229 + return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *) &ec_word, 2, 230 + NULL, 0); 231 + } else { 232 + unsigned char ec_byte = bits & 0xff; 233 + return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0); 234 + } 235 + } 236 + EXPORT_SYMBOL_GPL(olpc_ec_mask_write); 237 + 238 + int olpc_ec_sci_query(u16 *sci_value) 239 + { 240 + int ret; 241 + 242 + if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) { 243 + __be16 ec_word; 244 + ret = olpc_ec_cmd(EC_EXT_SCI_QUERY, 245 + NULL, 0, (void *) &ec_word, 2); 246 + if (ret == 0) 247 + *sci_value = be16_to_cpu(ec_word); 248 + } else { 249 + unsigned char ec_byte; 250 + ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1); 251 + if (ret == 0) 252 + *sci_value = ec_byte; 253 + } 254 + 255 + return ret; 256 + } 257 + EXPORT_SYMBOL_GPL(olpc_ec_sci_query); 258 + 259 + static int olpc_ec_suspend(void) 260 + { 261 + return olpc_ec_mask_write(ec_wakeup_mask); 262 + } 263 + 195 264 static bool __init check_ofw_architecture(struct device_node *root) 196 265 { 197 266 const char *olpc_arch; ··· 319 242 return 0; 320 243 } 321 244 245 + static struct syscore_ops olpc_syscore_ops = { 246 + .suspend = olpc_ec_suspend, 247 + }; 248 + 322 249 static int __init olpc_init(void) 323 250 { 324 251 int r = 0; ··· 347 266 !cs5535_has_vsa2()) 348 267 x86_init.pci.arch_init = pci_olpc_init; 349 268 #endif 269 + /* EC version 0x5f adds support for wide SCI mask */ 270 + if (olpc_platform_info.ecver >= 0x5f) 271 + olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI; 350 272 351 273 printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n", 352 274 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "", ··· 361 277 if (r) 362 278 return r; 363 279 } 280 + 281 + register_syscore_ops(&olpc_syscore_ops); 364 282 365 283 return 0; 366 284 }