summaryrefslogtreecommitdiff
path: root/drivers/platform/olpc
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2019-05-13 09:56:34 +0200
committerAndy Shevchenko <andriy.shevchenko@linux.intel.com>2019-05-20 17:27:08 +0300
commitec9964b4803300fb86f8e8fd9b421e59f7a71dc5 (patch)
tree5c770c4005c99a13f1dfb87f9a2c4ca4d99cf9c9 /drivers/platform/olpc
parent2dc78630497780b36975e5bcb69bbbf4d2ee0e46 (diff)
Platform: OLPC: Move EC-specific functionality out from x86
Move the olpc-ec driver away from the X86 OLPC platform so that it could be used by the ARM based laptops too. Notably, the driver for the OLPC battery, which is also used on the ARM models, builds on this driver's interface. It is actually plaform independent: the OLPC EC commands with their argument and responses are mostly the same despite the delivery mechanism is different. Signed-off-by: Lubomir Rintel <lkundrak@v3.sk> Acked-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Diffstat (limited to 'drivers/platform/olpc')
-rw-r--r--drivers/platform/olpc/olpc-ec.c99
1 files changed, 96 insertions, 3 deletions
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 981955dce926..2a647455a368 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -32,6 +32,7 @@ struct ec_cmd_desc {
struct olpc_ec_priv {
struct olpc_ec_driver *drv;
+ u8 version;
struct work_struct worker;
struct mutex cmd_lock;
@@ -42,6 +43,12 @@ struct olpc_ec_priv {
struct dentry *dbgfs_dir;
/*
+ * EC event mask to be applied during suspend (defining wakeup
+ * sources).
+ */
+ u16 ec_wakeup_mask;
+
+ /*
* Running an EC command while suspending means we don't always finish
* the command before the machine suspends. This means that the EC
* is expecting the command protocol to finish, but we after a period
@@ -149,6 +156,88 @@ int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
+void olpc_ec_wakeup_set(u16 value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return;
+
+ ec->ec_wakeup_mask |= value;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
+
+void olpc_ec_wakeup_clear(u16 value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return;
+
+ ec->ec_wakeup_mask &= ~value;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
+
+int olpc_ec_mask_write(u16 bits)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+
+ if (WARN_ON(!ec))
+ return -ENODEV;
+
+ /* EC version 0x5f adds support for wide SCI mask */
+ if (ec->version >= 0x5f) {
+ __be16 ec_word = cpu_to_be16(bits);
+
+ return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *)&ec_word, 2, NULL, 0);
+ } else {
+ u8 ec_byte = bits & 0xff;
+
+ return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
+ }
+}
+EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
+
+/*
+ * Returns true if the compile and runtime configurations allow for EC events
+ * to wake the system.
+ */
+bool olpc_ec_wakeup_available(void)
+{
+ if (WARN_ON(!ec_driver))
+ return false;
+
+ return ec_driver->wakeup_available;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
+
+int olpc_ec_sci_query(u16 *sci_value)
+{
+ struct olpc_ec_priv *ec = ec_priv;
+ int ret;
+
+ if (WARN_ON(!ec))
+ return -ENODEV;
+
+ /* EC version 0x5f adds support for wide SCI mask */
+ if (ec->version >= 0x5f) {
+ __be16 ec_word;
+
+ ret = olpc_ec_cmd(EC_EXT_SCI_QUERY, NULL, 0, (void *)&ec_word, 2);
+ if (ret == 0)
+ *sci_value = be16_to_cpu(ec_word);
+ } else {
+ u8 ec_byte;
+
+ ret = olpc_ec_cmd(EC_SCI_QUERY, NULL, 0, &ec_byte, 1);
+ if (ret == 0)
+ *sci_value = ec_byte;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
+
#ifdef CONFIG_DEBUG_FS
/*
@@ -276,14 +365,16 @@ static int olpc_ec_probe(struct platform_device *pdev)
ec_priv = ec;
platform_set_drvdata(pdev, ec);
- err = ec_driver->probe ? ec_driver->probe(pdev) : 0;
+ /* get the EC revision */
+ err = olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0, &ec->version, 1);
if (err) {
ec_priv = NULL;
kfree(ec);
- } else {
- ec->dbgfs_dir = olpc_ec_setup_debugfs();
+ return err;
}
+ ec->dbgfs_dir = olpc_ec_setup_debugfs();
+
return err;
}
@@ -293,6 +384,8 @@ static int olpc_ec_suspend(struct device *dev)
struct olpc_ec_priv *ec = platform_get_drvdata(pdev);
int err = 0;
+ olpc_ec_mask_write(ec->ec_wakeup_mask);
+
if (ec_driver->suspend)
err = ec_driver->suspend(pdev);
if (!err)