Commit ec9964b4 authored by Lubomir Rintel's avatar Lubomir Rintel Committed by Andy Shevchenko

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: default avatarLubomir Rintel <lkundrak@v3.sk>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
parent 2dc78630
...@@ -9,12 +9,10 @@ ...@@ -9,12 +9,10 @@
struct olpc_platform_t { struct olpc_platform_t {
int flags; int flags;
uint32_t boardrev; uint32_t boardrev;
int ecver;
}; };
#define OLPC_F_PRESENT 0x01 #define OLPC_F_PRESENT 0x01
#define OLPC_F_DCON 0x02 #define OLPC_F_DCON 0x02
#define OLPC_F_EC_WIDE_SCI 0x04
#ifdef CONFIG_OLPC #ifdef CONFIG_OLPC
...@@ -64,13 +62,6 @@ static inline int olpc_board_at_least(uint32_t rev) ...@@ -64,13 +62,6 @@ static inline int olpc_board_at_least(uint32_t rev)
return olpc_platform_info.boardrev >= rev; return olpc_platform_info.boardrev >= rev;
} }
extern void olpc_ec_wakeup_set(u16 value);
extern void olpc_ec_wakeup_clear(u16 value);
extern bool olpc_ec_wakeup_available(void);
extern int olpc_ec_mask_write(u16 bits);
extern int olpc_ec_sci_query(u16 *sci_value);
#else #else
static inline int machine_is_olpc(void) static inline int machine_is_olpc(void)
...@@ -83,14 +74,6 @@ static inline int olpc_has_dcon(void) ...@@ -83,14 +74,6 @@ static inline int olpc_has_dcon(void)
return 0; return 0;
} }
static inline void olpc_ec_wakeup_set(u16 value) { }
static inline void olpc_ec_wakeup_clear(u16 value) { }
static inline bool olpc_ec_wakeup_available(void)
{
return false;
}
#endif #endif
#ifdef CONFIG_OLPC_XO1_PM #ifdef CONFIG_OLPC_XO1_PM
...@@ -101,20 +84,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value); ...@@ -101,20 +84,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value);
extern int pci_olpc_init(void); extern int pci_olpc_init(void);
/* SCI source values */
#define EC_SCI_SRC_EMPTY 0x00
#define EC_SCI_SRC_GAME 0x01
#define EC_SCI_SRC_BATTERY 0x02
#define EC_SCI_SRC_BATSOC 0x04
#define EC_SCI_SRC_BATERR 0x08
#define EC_SCI_SRC_EBOOK 0x10 /* XO-1 only */
#define EC_SCI_SRC_WLAN 0x20 /* XO-1 only */
#define EC_SCI_SRC_ACPWR 0x40
#define EC_SCI_SRC_BATCRIT 0x80
#define EC_SCI_SRC_GPWAKE 0x100 /* XO-1.5 only */
#define EC_SCI_SRC_ALL 0x1FF
/* GPIO assignments */ /* GPIO assignments */
#define OLPC_GPIO_MIC_AC 1 #define OLPC_GPIO_MIC_AC 1
......
...@@ -30,9 +30,6 @@ ...@@ -30,9 +30,6 @@
struct olpc_platform_t olpc_platform_info; struct olpc_platform_t olpc_platform_info;
EXPORT_SYMBOL_GPL(olpc_platform_info); EXPORT_SYMBOL_GPL(olpc_platform_info);
/* EC event mask to be applied during suspend (defining wakeup sources). */
static u16 ec_wakeup_mask;
/* what the timeout *should* be (in ms) */ /* what the timeout *should* be (in ms) */
#define EC_BASE_TIMEOUT 20 #define EC_BASE_TIMEOUT 20
...@@ -186,83 +183,6 @@ static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, ...@@ -186,83 +183,6 @@ static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
return ret; return ret;
} }
void olpc_ec_wakeup_set(u16 value)
{
ec_wakeup_mask |= value;
}
EXPORT_SYMBOL_GPL(olpc_ec_wakeup_set);
void olpc_ec_wakeup_clear(u16 value)
{
ec_wakeup_mask &= ~value;
}
EXPORT_SYMBOL_GPL(olpc_ec_wakeup_clear);
/*
* Returns true if the compile and runtime configurations allow for EC events
* to wake the system.
*/
bool olpc_ec_wakeup_available(void)
{
if (!machine_is_olpc())
return false;
/*
* XO-1 EC wakeups are available when olpc-xo1-sci driver is
* compiled in
*/
#ifdef CONFIG_OLPC_XO1_SCI
if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) /* XO-1 */
return true;
#endif
/*
* XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
* compiled in
*/
#ifdef CONFIG_OLPC_XO15_SCI
if (olpc_platform_info.boardrev >= olpc_board_pre(0xd0)) /* XO-1.5 */
return true;
#endif
return false;
}
EXPORT_SYMBOL_GPL(olpc_ec_wakeup_available);
int olpc_ec_mask_write(u16 bits)
{
if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
__be16 ec_word = cpu_to_be16(bits);
return olpc_ec_cmd(EC_WRITE_EXT_SCI_MASK, (void *) &ec_word, 2,
NULL, 0);
} else {
unsigned char ec_byte = bits & 0xff;
return olpc_ec_cmd(EC_WRITE_SCI_MASK, &ec_byte, 1, NULL, 0);
}
}
EXPORT_SYMBOL_GPL(olpc_ec_mask_write);
int olpc_ec_sci_query(u16 *sci_value)
{
int ret;
if (olpc_platform_info.flags & OLPC_F_EC_WIDE_SCI) {
__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 {
unsigned char 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);
static bool __init check_ofw_architecture(struct device_node *root) static bool __init check_ofw_architecture(struct device_node *root)
{ {
const char *olpc_arch; const char *olpc_arch;
...@@ -296,6 +216,10 @@ static bool __init platform_detect(void) ...@@ -296,6 +216,10 @@ static bool __init platform_detect(void)
if (success) { if (success) {
olpc_platform_info.boardrev = get_board_revision(root); olpc_platform_info.boardrev = get_board_revision(root);
olpc_platform_info.flags |= OLPC_F_PRESENT; olpc_platform_info.flags |= OLPC_F_PRESENT;
pr_info("OLPC board revision %s%X\n",
((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
olpc_platform_info.boardrev >> 4);
} }
of_node_put(root); of_node_put(root);
...@@ -315,27 +239,8 @@ static int __init add_xo1_platform_devices(void) ...@@ -315,27 +239,8 @@ static int __init add_xo1_platform_devices(void)
return PTR_ERR_OR_ZERO(pdev); return PTR_ERR_OR_ZERO(pdev);
} }
static int olpc_xo1_ec_probe(struct platform_device *pdev)
{
/* get the EC revision */
olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
(unsigned char *) &olpc_platform_info.ecver, 1);
/* EC version 0x5f adds support for wide SCI mask */
if (olpc_platform_info.ecver >= 0x5f)
olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;
pr_info("OLPC board revision %s%X (EC=%x)\n",
((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
olpc_platform_info.boardrev >> 4,
olpc_platform_info.ecver);
return 0;
}
static int olpc_xo1_ec_suspend(struct platform_device *pdev) static int olpc_xo1_ec_suspend(struct platform_device *pdev)
{ {
olpc_ec_mask_write(ec_wakeup_mask);
/* /*
* Squelch SCIs while suspended. This is a fix for * Squelch SCIs while suspended. This is a fix for
* <http://dev.laptop.org/ticket/1835>. * <http://dev.laptop.org/ticket/1835>.
...@@ -359,15 +264,27 @@ static int olpc_xo1_ec_resume(struct platform_device *pdev) ...@@ -359,15 +264,27 @@ static int olpc_xo1_ec_resume(struct platform_device *pdev)
} }
static struct olpc_ec_driver ec_xo1_driver = { static struct olpc_ec_driver ec_xo1_driver = {
.probe = olpc_xo1_ec_probe,
.suspend = olpc_xo1_ec_suspend, .suspend = olpc_xo1_ec_suspend,
.resume = olpc_xo1_ec_resume, .resume = olpc_xo1_ec_resume,
.ec_cmd = olpc_xo1_ec_cmd, .ec_cmd = olpc_xo1_ec_cmd,
#ifdef CONFIG_OLPC_XO1_SCI
/*
* XO-1 EC wakeups are available when olpc-xo1-sci driver is
* compiled in
*/
.wakeup_available = true,
#endif
}; };
static struct olpc_ec_driver ec_xo1_5_driver = { static struct olpc_ec_driver ec_xo1_5_driver = {
.probe = olpc_xo1_ec_probe,
.ec_cmd = olpc_xo1_ec_cmd, .ec_cmd = olpc_xo1_ec_cmd,
#ifdef CONFIG_OLPC_XO1_5_SCI
/*
* XO-1.5 EC wakeups are available when olpc-xo15-sci driver is
* compiled in
*/
.wakeup_available = true,
#endif
}; };
static int __init olpc_init(void) static int __init olpc_init(void)
......
...@@ -32,6 +32,7 @@ struct ec_cmd_desc { ...@@ -32,6 +32,7 @@ struct ec_cmd_desc {
struct olpc_ec_priv { struct olpc_ec_priv {
struct olpc_ec_driver *drv; struct olpc_ec_driver *drv;
u8 version;
struct work_struct worker; struct work_struct worker;
struct mutex cmd_lock; struct mutex cmd_lock;
...@@ -41,6 +42,12 @@ struct olpc_ec_priv { ...@@ -41,6 +42,12 @@ struct olpc_ec_priv {
struct dentry *dbgfs_dir; 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 * Running an EC command while suspending means we don't always finish
* the command before the machine suspends. This means that the EC * the command before the machine suspends. This means that the EC
...@@ -149,6 +156,88 @@ int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen) ...@@ -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); 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 #ifdef CONFIG_DEBUG_FS
/* /*
...@@ -276,14 +365,16 @@ static int olpc_ec_probe(struct platform_device *pdev) ...@@ -276,14 +365,16 @@ static int olpc_ec_probe(struct platform_device *pdev)
ec_priv = ec; ec_priv = ec;
platform_set_drvdata(pdev, 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) { if (err) {
ec_priv = NULL; ec_priv = NULL;
kfree(ec); kfree(ec);
} else { return err;
ec->dbgfs_dir = olpc_ec_setup_debugfs();
} }
ec->dbgfs_dir = olpc_ec_setup_debugfs();
return err; return err;
} }
...@@ -293,6 +384,8 @@ static int olpc_ec_suspend(struct device *dev) ...@@ -293,6 +384,8 @@ static int olpc_ec_suspend(struct device *dev)
struct olpc_ec_priv *ec = platform_get_drvdata(pdev); struct olpc_ec_priv *ec = platform_get_drvdata(pdev);
int err = 0; int err = 0;
olpc_ec_mask_write(ec->ec_wakeup_mask);
if (ec_driver->suspend) if (ec_driver->suspend)
err = ec_driver->suspend(pdev); err = ec_driver->suspend(pdev);
if (!err) if (!err)
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/olpc-ec.h> #include <linux/olpc-ec.h>
#include <asm/olpc.h>
#define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */ #define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
......
...@@ -16,14 +16,28 @@ ...@@ -16,14 +16,28 @@
#define EC_SCI_QUERY 0x84 #define EC_SCI_QUERY 0x84
#define EC_EXT_SCI_QUERY 0x85 #define EC_EXT_SCI_QUERY 0x85
/* SCI source values */
#define EC_SCI_SRC_EMPTY 0x00
#define EC_SCI_SRC_GAME 0x01
#define EC_SCI_SRC_BATTERY 0x02
#define EC_SCI_SRC_BATSOC 0x04
#define EC_SCI_SRC_BATERR 0x08
#define EC_SCI_SRC_EBOOK 0x10 /* XO-1 only */
#define EC_SCI_SRC_WLAN 0x20 /* XO-1 only */
#define EC_SCI_SRC_ACPWR 0x40
#define EC_SCI_SRC_BATCRIT 0x80
#define EC_SCI_SRC_GPWAKE 0x100 /* XO-1.5 only */
#define EC_SCI_SRC_ALL 0x1FF
struct platform_device; struct platform_device;
struct olpc_ec_driver { struct olpc_ec_driver {
int (*probe)(struct platform_device *);
int (*suspend)(struct platform_device *); int (*suspend)(struct platform_device *);
int (*resume)(struct platform_device *); int (*resume)(struct platform_device *);
int (*ec_cmd)(u8, u8 *, size_t, u8 *, size_t, void *); int (*ec_cmd)(u8, u8 *, size_t, u8 *, size_t, void *);
bool wakeup_available;
}; };
#ifdef CONFIG_OLPC #ifdef CONFIG_OLPC
...@@ -33,11 +47,27 @@ extern void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg); ...@@ -33,11 +47,27 @@ extern void olpc_ec_driver_register(struct olpc_ec_driver *drv, void *arg);
extern int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, extern int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
size_t outlen); size_t outlen);
extern void olpc_ec_wakeup_set(u16 value);
extern void olpc_ec_wakeup_clear(u16 value);
extern int olpc_ec_mask_write(u16 bits);
extern int olpc_ec_sci_query(u16 *sci_value);
extern bool olpc_ec_wakeup_available(void);
#else #else
static inline int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, static inline int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
size_t outlen) { return -ENODEV; } size_t outlen) { return -ENODEV; }
static inline void olpc_ec_wakeup_set(u16 value) { }
static inline void olpc_ec_wakeup_clear(u16 value) { }
static inline bool olpc_ec_wakeup_available(void)
{
return false;
}
#endif /* CONFIG_OLPC */ #endif /* CONFIG_OLPC */
#endif /* _LINUX_OLPC_EC_H */ #endif /* _LINUX_OLPC_EC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment