Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc6bdb59 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus-3.6' of git://dev.laptop.org/users/dilinger/linux-olpc

Pull OLPC platform updates from Andres Salomon:
 "These move the OLPC Embedded Controller driver out of
  arch/x86/platform and into drivers/platform/olpc.

  OLPC machines are now ARM-based (which means lots of x86 and ARM
  changes), but are typically pretty self-contained..  so it makes more
  sense to go through a separate OLPC tree after getting the appropriate
  review/ACKs."

* 'for-linus-3.6' of git://dev.laptop.org/users/dilinger/linux-olpc:
  x86: OLPC: move s/r-related EC cmds to EC driver
  Platform: OLPC: move global variables into priv struct
  Platform: OLPC: move debugfs support from x86 EC driver
  x86: OLPC: switch over to using new EC driver on x86
  Platform: OLPC: add a suspended flag to the EC driver
  Platform: OLPC: turn EC driver into a platform_driver
  Platform: OLPC: allow EC cmd to be overridden, and create a workqueue to call it
  drivers: OLPC: update various drivers to include olpc-ec.h
  Platform: OLPC: add a stub to drivers/platform/ for the OLPC EC driver
parents 44d82e29 1fcfd08b
Loading
Loading
Loading
Loading
+0 −19
Original line number Original line Diff line number Diff line
@@ -100,25 +100,6 @@ extern void olpc_xo1_pm_wakeup_clear(u16 value);


extern int pci_olpc_init(void);
extern int pci_olpc_init(void);


/* EC related functions */

extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
		unsigned char *outbuf, size_t outlen);

/* EC commands */

#define EC_FIRMWARE_REV			0x08
#define EC_WRITE_SCI_MASK		0x1b
#define EC_WAKE_UP_WLAN			0x24
#define EC_WLAN_LEAVE_RESET		0x25
#define EC_READ_EB_MODE			0x2a
#define EC_SET_SCI_INHIBIT		0x32
#define EC_SET_SCI_INHIBIT_RELEASE	0x34
#define EC_WLAN_ENTER_RESET		0x35
#define EC_WRITE_EXT_SCI_MASK		0x38
#define EC_SCI_QUERY			0x84
#define EC_EXT_SCI_QUERY		0x85

/* SCI source values */
/* SCI source values */


#define EC_SCI_SRC_EMPTY	0x00
#define EC_SCI_SRC_EMPTY	0x00
+1 −15
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/pm.h>
#include <linux/pm.h>
#include <linux/mfd/core.h>
#include <linux/mfd/core.h>
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/olpc-ec.h>


#include <asm/io.h>
#include <asm/io.h>
#include <asm/olpc.h>
#include <asm/olpc.h>
@@ -51,16 +52,11 @@ EXPORT_SYMBOL_GPL(olpc_xo1_pm_wakeup_clear);
static int xo1_power_state_enter(suspend_state_t pm_state)
static int xo1_power_state_enter(suspend_state_t pm_state)
{
{
	unsigned long saved_sci_mask;
	unsigned long saved_sci_mask;
	int r;


	/* Only STR is supported */
	/* Only STR is supported */
	if (pm_state != PM_SUSPEND_MEM)
	if (pm_state != PM_SUSPEND_MEM)
		return -EINVAL;
		return -EINVAL;


	r = olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
	if (r)
		return r;

	/*
	/*
	 * Save SCI mask (this gets lost since PM1_EN is used as a mask for
	 * Save SCI mask (this gets lost since PM1_EN is used as a mask for
	 * wakeup events, which is not necessarily the same event set)
	 * wakeup events, which is not necessarily the same event set)
@@ -76,16 +72,6 @@ static int xo1_power_state_enter(suspend_state_t pm_state)
	/* Restore SCI mask (using dword access to CS5536_PM1_EN) */
	/* Restore SCI mask (using dword access to CS5536_PM1_EN) */
	outl(saved_sci_mask, acpi_base + CS5536_PM1_STS);
	outl(saved_sci_mask, acpi_base + CS5536_PM1_STS);


	/* Tell the EC to stop inhibiting SCIs */
	olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);

	/*
	 * Tell the wireless module to restart USB communication.
	 * Must be done twice.
	 */
	olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
	olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);

	return 0;
	return 0;
}
}


+1 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/power_supply.h>
#include <linux/power_supply.h>
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/olpc-ec.h>


#include <asm/io.h>
#include <asm/io.h>
#include <asm/msr.h>
#include <asm/msr.h>
+1 −0
Original line number Original line Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/power_supply.h>
#include <linux/power_supply.h>
#include <linux/olpc-ec.h>


#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
+62 −128
Original line number Original line Diff line number Diff line
@@ -14,14 +14,13 @@
#include <linux/init.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/syscore_ops.h>
#include <linux/syscore_ops.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/olpc-ec.h>


#include <asm/geode.h>
#include <asm/geode.h>
#include <asm/setup.h>
#include <asm/setup.h>
@@ -31,17 +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);


static DEFINE_SPINLOCK(ec_lock);

/* debugfs interface to EC commands */
#define EC_MAX_CMD_ARGS (5 + 1)	/* cmd byte + 5 args */
#define EC_MAX_CMD_REPLY (8)

static struct dentry *ec_debugfs_dir;
static DEFINE_MUTEX(ec_debugfs_cmd_lock);
static unsigned char ec_debugfs_resp[EC_MAX_CMD_REPLY];
static unsigned int ec_debugfs_resp_bytes;

/* EC event mask to be applied during suspend (defining wakeup sources). */
/* EC event mask to be applied during suspend (defining wakeup sources). */
static u16 ec_wakeup_mask;
static u16 ec_wakeup_mask;


@@ -125,16 +113,13 @@ static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
 * <http://wiki.laptop.org/go/Ec_specification>.  Unfortunately, while
 * <http://wiki.laptop.org/go/Ec_specification>.  Unfortunately, while
 * OpenFirmware's source is available, the EC's is not.
 * OpenFirmware's source is available, the EC's is not.
 */
 */
int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
static int olpc_xo1_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf,
		unsigned char *outbuf,  size_t outlen)
		size_t outlen, void *arg)
{
{
	unsigned long flags;
	int ret = -EIO;
	int ret = -EIO;
	int i;
	int i;
	int restarts = 0;
	int restarts = 0;


	spin_lock_irqsave(&ec_lock, flags);

	/* Clear OBF */
	/* Clear OBF */
	for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
	for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
		inb(0x68);
		inb(0x68);
@@ -198,10 +183,8 @@ int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,


	ret = 0;
	ret = 0;
err:
err:
	spin_unlock_irqrestore(&ec_lock, flags);
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);


void olpc_ec_wakeup_set(u16 value)
void olpc_ec_wakeup_set(u16 value)
{
{
@@ -280,96 +263,6 @@ int olpc_ec_sci_query(u16 *sci_value)
}
}
EXPORT_SYMBOL_GPL(olpc_ec_sci_query);
EXPORT_SYMBOL_GPL(olpc_ec_sci_query);


static ssize_t ec_debugfs_cmd_write(struct file *file, const char __user *buf,
				    size_t size, loff_t *ppos)
{
	int i, m;
	unsigned char ec_cmd[EC_MAX_CMD_ARGS];
	unsigned int ec_cmd_int[EC_MAX_CMD_ARGS];
	char cmdbuf[64];
	int ec_cmd_bytes;

	mutex_lock(&ec_debugfs_cmd_lock);

	size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size);

	m = sscanf(cmdbuf, "%x:%u %x %x %x %x %x", &ec_cmd_int[0],
		   &ec_debugfs_resp_bytes,
		   &ec_cmd_int[1], &ec_cmd_int[2], &ec_cmd_int[3],
		   &ec_cmd_int[4], &ec_cmd_int[5]);
	if (m < 2 || ec_debugfs_resp_bytes > EC_MAX_CMD_REPLY) {
		/* reset to prevent overflow on read */
		ec_debugfs_resp_bytes = 0;

		printk(KERN_DEBUG "olpc-ec: bad ec cmd:  "
		       "cmd:response-count [arg1 [arg2 ...]]\n");
		size = -EINVAL;
		goto out;
	}

	/* convert scanf'd ints to char */
	ec_cmd_bytes = m - 2;
	for (i = 0; i <= ec_cmd_bytes; i++)
		ec_cmd[i] = ec_cmd_int[i];

	printk(KERN_DEBUG "olpc-ec: debugfs cmd 0x%02x with %d args "
	       "%02x %02x %02x %02x %02x, want %d returns\n",
	       ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2], ec_cmd[3],
	       ec_cmd[4], ec_cmd[5], ec_debugfs_resp_bytes);

	olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
		    ec_cmd_bytes, ec_debugfs_resp, ec_debugfs_resp_bytes);

	printk(KERN_DEBUG "olpc-ec: response "
	       "%02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n",
	       ec_debugfs_resp[0], ec_debugfs_resp[1], ec_debugfs_resp[2],
	       ec_debugfs_resp[3], ec_debugfs_resp[4], ec_debugfs_resp[5],
	       ec_debugfs_resp[6], ec_debugfs_resp[7], ec_debugfs_resp_bytes);

out:
	mutex_unlock(&ec_debugfs_cmd_lock);
	return size;
}

static ssize_t ec_debugfs_cmd_read(struct file *file, char __user *buf,
				   size_t size, loff_t *ppos)
{
	unsigned int i, r;
	char *rp;
	char respbuf[64];

	mutex_lock(&ec_debugfs_cmd_lock);
	rp = respbuf;
	rp += sprintf(rp, "%02x", ec_debugfs_resp[0]);
	for (i = 1; i < ec_debugfs_resp_bytes; i++)
		rp += sprintf(rp, ", %02x", ec_debugfs_resp[i]);
	mutex_unlock(&ec_debugfs_cmd_lock);
	rp += sprintf(rp, "\n");

	r = rp - respbuf;
	return simple_read_from_buffer(buf, size, ppos, respbuf, r);
}

static const struct file_operations ec_debugfs_genops = {
	.write	 = ec_debugfs_cmd_write,
	.read	 = ec_debugfs_cmd_read,
};

static void setup_debugfs(void)
{
	ec_debugfs_dir = debugfs_create_dir("olpc-ec", 0);
	if (ec_debugfs_dir == ERR_PTR(-ENODEV))
		return;

	debugfs_create_file("cmd", 0600, ec_debugfs_dir, NULL,
			    &ec_debugfs_genops);
}

static int olpc_ec_suspend(void)
{
	return olpc_ec_mask_write(ec_wakeup_mask);
}

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;
@@ -424,8 +317,59 @@ static int __init add_xo1_platform_devices(void)
	return 0;
	return 0;
}
}


static struct syscore_ops olpc_syscore_ops = {
static int olpc_xo1_ec_probe(struct platform_device *pdev)
	.suspend = olpc_ec_suspend,
{
	/* 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>.
	 */
	return olpc_ec_cmd(EC_SET_SCI_INHIBIT, NULL, 0, NULL, 0);
}

static int olpc_xo1_ec_resume(struct platform_device *pdev)
{
	/* Tell the EC to stop inhibiting SCIs */
	olpc_ec_cmd(EC_SET_SCI_INHIBIT_RELEASE, NULL, 0, NULL, 0);

	/*
	 * Tell the wireless module to restart USB communication.
	 * Must be done twice.
	 */
	olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);
	olpc_ec_cmd(EC_WAKE_UP_WLAN, NULL, 0, NULL, 0);

	return 0;
}

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,
};

static struct olpc_ec_driver ec_xo1_5_driver = {
	.probe = olpc_xo1_ec_probe,
	.ec_cmd = olpc_xo1_ec_cmd,
};
};


static int __init olpc_init(void)
static int __init olpc_init(void)
@@ -435,16 +379,17 @@ static int __init olpc_init(void)
	if (!olpc_ofw_present() || !platform_detect())
	if (!olpc_ofw_present() || !platform_detect())
		return 0;
		return 0;


	spin_lock_init(&ec_lock);
	/* register the XO-1 and 1.5-specific EC handler */
	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0))	/* XO-1 */
		olpc_ec_driver_register(&ec_xo1_driver, NULL);
	else
		olpc_ec_driver_register(&ec_xo1_5_driver, NULL);
	platform_device_register_simple("olpc-ec", -1, NULL, 0);


	/* assume B1 and above models always have a DCON */
	/* assume B1 and above models always have a DCON */
	if (olpc_board_at_least(olpc_board(0xb1)))
	if (olpc_board_at_least(olpc_board(0xb1)))
		olpc_platform_info.flags |= OLPC_F_DCON;
		olpc_platform_info.flags |= OLPC_F_DCON;


	/* get the EC revision */
	olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
			(unsigned char *) &olpc_platform_info.ecver, 1);

#ifdef CONFIG_PCI_OLPC
#ifdef CONFIG_PCI_OLPC
	/* If the VSA exists let it emulate PCI, if not emulate in kernel.
	/* If the VSA exists let it emulate PCI, if not emulate in kernel.
	 * XO-1 only. */
	 * XO-1 only. */
@@ -452,14 +397,6 @@ static int __init olpc_init(void)
			!cs5535_has_vsa2())
			!cs5535_has_vsa2())
		x86_init.pci.arch_init = pci_olpc_init;
		x86_init.pci.arch_init = pci_olpc_init;
#endif
#endif
	/* EC version 0x5f adds support for wide SCI mask */
	if (olpc_platform_info.ecver >= 0x5f)
		olpc_platform_info.flags |= OLPC_F_EC_WIDE_SCI;

	printk(KERN_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);


	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
	if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
		r = add_xo1_platform_devices();
		r = add_xo1_platform_devices();
@@ -467,9 +404,6 @@ static int __init olpc_init(void)
			return r;
			return r;
	}
	}


	register_syscore_ops(&olpc_syscore_ops);
	setup_debugfs();

	return 0;
	return 0;
}
}


Loading