Skip to content

Commit

Permalink
Platform: OLPC: Move EC-specific functionality out from x86
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lubomir Rintel authored and Andy Shevchenko committed May 20, 2019
1 parent 2dc7863 commit ec9964b
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 137 deletions.
31 changes: 0 additions & 31 deletions arch/x86/include/asm/olpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
struct olpc_platform_t {
int flags;
uint32_t boardrev;
int ecver;
};

#define OLPC_F_PRESENT 0x01
#define OLPC_F_DCON 0x02
#define OLPC_F_EC_WIDE_SCI 0x04

#ifdef CONFIG_OLPC

Expand Down Expand Up @@ -64,13 +62,6 @@ static inline int olpc_board_at_least(uint32_t 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

static inline int machine_is_olpc(void)
Expand All @@ -83,14 +74,6 @@ static inline int olpc_has_dcon(void)
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

#ifdef CONFIG_OLPC_XO1_PM
Expand All @@ -101,20 +84,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value);

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 */

#define OLPC_GPIO_MIC_AC 1
Expand Down
119 changes: 18 additions & 101 deletions arch/x86/platform/olpc/olpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@
struct olpc_platform_t 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) */
#define EC_BASE_TIMEOUT 20

Expand Down Expand Up @@ -186,83 +183,6 @@ static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
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)
{
const char *olpc_arch;
Expand Down Expand Up @@ -296,6 +216,10 @@ static bool __init platform_detect(void)
if (success) {
olpc_platform_info.boardrev = get_board_revision(root);
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);
Expand All @@ -315,27 +239,8 @@ static int __init add_xo1_platform_devices(void)
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)
{
olpc_ec_mask_write(ec_wakeup_mask);

/*
* Squelch SCIs while suspended. This is a fix for
* <http://dev.laptop.org/ticket/1835>.
Expand All @@ -359,15 +264,27 @@ static int olpc_xo1_ec_resume(struct platform_device *pdev)
}

static struct olpc_ec_driver ec_xo1_driver = {
.probe = olpc_xo1_ec_probe,
.suspend = olpc_xo1_ec_suspend,
.resume = olpc_xo1_ec_resume,
.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 = {
.probe = olpc_xo1_ec_probe,
.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)
Expand Down
99 changes: 96 additions & 3 deletions drivers/platform/olpc/olpc-ec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -41,6 +42,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
Expand Down Expand Up @@ -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

/*
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)
Expand Down
1 change: 0 additions & 1 deletion drivers/power/supply/olpc_battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/olpc-ec.h>
#include <asm/olpc.h>


#define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
Expand Down
Loading

0 comments on commit ec9964b

Please sign in to comment.