0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/init.h>
0011 #include <linux/export.h>
0012 #include <linux/delay.h>
0013 #include <linux/io.h>
0014 #include <linux/string.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/of.h>
0017 #include <linux/syscore_ops.h>
0018 #include <linux/mutex.h>
0019 #include <linux/olpc-ec.h>
0020
0021 #include <asm/geode.h>
0022 #include <asm/setup.h>
0023 #include <asm/olpc.h>
0024 #include <asm/olpc_ofw.h>
0025
0026 struct olpc_platform_t olpc_platform_info;
0027 EXPORT_SYMBOL_GPL(olpc_platform_info);
0028
0029
0030 #define EC_BASE_TIMEOUT 20
0031
0032
0033 static int ec_timeout = EC_BASE_TIMEOUT;
0034
0035 static int __init olpc_ec_timeout_set(char *str)
0036 {
0037 if (get_option(&str, &ec_timeout) != 1) {
0038 ec_timeout = EC_BASE_TIMEOUT;
0039 printk(KERN_ERR "olpc-ec: invalid argument to "
0040 "'olpc_ec_timeout=', ignoring!\n");
0041 }
0042 printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
0043 ec_timeout);
0044 return 1;
0045 }
0046 __setup("olpc_ec_timeout=", olpc_ec_timeout_set);
0047
0048
0049
0050
0051
0052 static inline unsigned int ibf_status(unsigned int port)
0053 {
0054 return !!(inb(port) & 0x02);
0055 }
0056
0057 static inline unsigned int obf_status(unsigned int port)
0058 {
0059 return inb(port) & 0x01;
0060 }
0061
0062 #define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
0063 static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
0064 {
0065 unsigned int timeo;
0066 int state = ibf_status(port);
0067
0068 for (timeo = ec_timeout; state != desired && timeo; timeo--) {
0069 mdelay(1);
0070 state = ibf_status(port);
0071 }
0072
0073 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
0074 timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
0075 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
0076 line, ec_timeout - timeo);
0077 }
0078
0079 return !(state == desired);
0080 }
0081
0082 #define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
0083 static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
0084 {
0085 unsigned int timeo;
0086 int state = obf_status(port);
0087
0088 for (timeo = ec_timeout; state != desired && timeo; timeo--) {
0089 mdelay(1);
0090 state = obf_status(port);
0091 }
0092
0093 if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
0094 timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
0095 printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
0096 line, ec_timeout - timeo);
0097 }
0098
0099 return !(state == desired);
0100 }
0101
0102
0103
0104
0105
0106
0107
0108
0109 static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
0110 size_t outlen, void *arg)
0111 {
0112 int ret = -EIO;
0113 int i;
0114 int restarts = 0;
0115
0116
0117 for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
0118 inb(0x68);
0119 if (i == 10) {
0120 printk(KERN_ERR "olpc-ec: timeout while attempting to "
0121 "clear OBF flag!\n");
0122 goto err;
0123 }
0124
0125 if (wait_on_ibf(0x6c, 0)) {
0126 printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
0127 "quiesce!\n");
0128 goto err;
0129 }
0130
0131 restart:
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 pr_devel("olpc-ec: running cmd 0x%x\n", cmd);
0142 outb(cmd, 0x6c);
0143
0144 if (wait_on_ibf(0x6c, 0)) {
0145 printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
0146 "command!\n");
0147 goto err;
0148 }
0149
0150 if (inbuf && inlen) {
0151
0152 for (i = 0; i < inlen; i++) {
0153 pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
0154 outb(inbuf[i], 0x68);
0155 if (wait_on_ibf(0x6c, 0)) {
0156 printk(KERN_ERR "olpc-ec: timeout waiting for"
0157 " EC accept data!\n");
0158 goto err;
0159 }
0160 }
0161 }
0162 if (outbuf && outlen) {
0163
0164 for (i = 0; i < outlen; i++) {
0165 if (wait_on_obf(0x6c, 1)) {
0166 printk(KERN_ERR "olpc-ec: timeout waiting for"
0167 " EC to provide data!\n");
0168 if (restarts++ < 10)
0169 goto restart;
0170 goto err;
0171 }
0172 outbuf[i] = inb(0x68);
0173 pr_devel("olpc-ec: received 0x%x\n", outbuf[i]);
0174 }
0175 }
0176
0177 ret = 0;
0178 err:
0179 return ret;
0180 }
0181
0182 static bool __init check_ofw_architecture(struct device_node *root)
0183 {
0184 const char *olpc_arch;
0185 int propsize;
0186
0187 olpc_arch = of_get_property(root, "architecture", &propsize);
0188 return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
0189 }
0190
0191 static u32 __init get_board_revision(struct device_node *root)
0192 {
0193 int propsize;
0194 const __be32 *rev;
0195
0196 rev = of_get_property(root, "board-revision-int", &propsize);
0197 if (propsize != 4)
0198 return 0;
0199
0200 return be32_to_cpu(*rev);
0201 }
0202
0203 static bool __init platform_detect(void)
0204 {
0205 struct device_node *root = of_find_node_by_path("/");
0206 bool success;
0207
0208 if (!root)
0209 return false;
0210
0211 success = check_ofw_architecture(root);
0212 if (success) {
0213 olpc_platform_info.boardrev = get_board_revision(root);
0214 olpc_platform_info.flags |= OLPC_F_PRESENT;
0215
0216 pr_info("OLPC board revision %s%X\n",
0217 ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
0218 olpc_platform_info.boardrev >> 4);
0219 }
0220
0221 of_node_put(root);
0222 return success;
0223 }
0224
0225 static int __init add_xo1_platform_devices(void)
0226 {
0227 struct platform_device *pdev;
0228
0229 pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
0230 if (IS_ERR(pdev))
0231 return PTR_ERR(pdev);
0232
0233 pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
0234
0235 return PTR_ERR_OR_ZERO(pdev);
0236 }
0237
0238 static int olpc_xo1_ec_suspend(struct platform_device *pdev)
0239 {
0240
0241
0242
0243
0244 return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
0245 }
0246
0247 static int olpc_xo1_ec_resume(struct platform_device *pdev)
0248 {
0249
0250 olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);
0251
0252
0253
0254
0255
0256 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
0257 olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
0258
0259 return 0;
0260 }
0261
0262 static struct olpc_ec_driver ec_xo1_driver = {
0263 .suspend = olpc_xo1_ec_suspend,
0264 .resume = olpc_xo1_ec_resume,
0265 .ec_cmd = olpc_xo1_ec_cmd,
0266 #ifdef CONFIG_OLPC_XO1_SCI
0267
0268
0269
0270
0271 .wakeup_available = true,
0272 #endif
0273 };
0274
0275 static struct olpc_ec_driver ec_xo1_5_driver = {
0276 .ec_cmd = olpc_xo1_ec_cmd,
0277 #ifdef CONFIG_OLPC_XO15_SCI
0278
0279
0280
0281
0282 .wakeup_available = true,
0283 #endif
0284 };
0285
0286 static int __init olpc_init(void)
0287 {
0288 int r = 0;
0289
0290 if (!olpc_ofw_present() || !platform_detect())
0291 return 0;
0292
0293
0294 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0))
0295 olpc_ec_driver_register(&ec_xo1_driver, NULL);
0296 else
0297 olpc_ec_driver_register(&ec_xo1_5_driver, NULL);
0298 platform_device_register_simple("olpc-ec", -1, NULL, 0);
0299
0300
0301 if (olpc_board_at_least(olpc_board(0xb1)))
0302 olpc_platform_info.flags |= OLPC_F_DCON;
0303
0304 #ifdef CONFIG_PCI_OLPC
0305
0306
0307 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
0308 !cs5535_has_vsa2())
0309 x86_init.pci.arch_init = pci_olpc_init;
0310 #endif
0311
0312 if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) {
0313 r = add_xo1_platform_devices();
0314 if (r)
0315 return r;
0316 }
0317
0318 return 0;
0319 }
0320
0321 postcore_initcall(olpc_init);