/*
 * Alchemy Development Board example suspend userspace interface.
 *
 * (c) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
 */

#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/suspend.h>
#include <linux/sysfs.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/gpio-au1000.h>
#include <asm/mach-db1x00/bcsr.h>

/*
 * Generic suspend userspace interface for Alchemy development boards.
 * This code exports a few sysfs nodes under /sys/power/db1x/ which
 * can be used by userspace to en/disable all au1x-provided wakeup
 * sources and configure the timeout after which the the TOYMATCH2 irq
 * is to trigger a wakeup.
 */


static unsigned long db1x_pm_sleep_secs;
static unsigned long db1x_pm_wakemsk;
static unsigned long db1x_pm_last_wakesrc;

static int db1x_pm_enter(suspend_state_t state)
{
	unsigned short bcsrs[16];
	int i, j, hasint;

	/* save CPLD regs */
	hasint = bcsr_read(BCSR_WHOAMI);
	hasint = BCSR_WHOAMI_BOARD(hasint) >= BCSR_WHOAMI_DB1200;
	j = (hasint) ? BCSR_MASKSET : BCSR_SYSTEM;

	for (i = BCSR_STATUS; i <= j; i++)
		bcsrs[i] = bcsr_read(i);

	/* shut off hexleds */
	bcsr_write(BCSR_HEXCLEAR, 3);

	/* enable GPIO based wakeup */
	alchemy_gpio1_input_enable();

	/* clear and setup wake cause and source */
	alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
	alchemy_wrsys(0, AU1000_SYS_WAKESRC);

	alchemy_wrsys(db1x_pm_wakemsk, AU1000_SYS_WAKEMSK);

	/* setup 1Hz-timer-based wakeup: wait for reg access */
	while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
		asm volatile ("nop");

	alchemy_wrsys(alchemy_rdsys(AU1000_SYS_TOYREAD) + db1x_pm_sleep_secs,
		      AU1000_SYS_TOYMATCH2);

	/* wait for value to really hit the register */
	while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
		asm volatile ("nop");

	/* ...and now the sandman can come! */
	au_sleep();


	/* restore CPLD regs */
	for (i = BCSR_STATUS; i <= BCSR_SYSTEM; i++)
		bcsr_write(i, bcsrs[i]);

	/* restore CPLD int registers */
	if (hasint) {
		bcsr_write(BCSR_INTCLR, 0xffff);
		bcsr_write(BCSR_MASKCLR, 0xffff);
		bcsr_write(BCSR_INTSTAT, 0xffff);
		bcsr_write(BCSR_INTSET, bcsrs[BCSR_INTSET]);
		bcsr_write(BCSR_MASKSET, bcsrs[BCSR_MASKSET]);
	}

	/* light up hexleds */
	bcsr_write(BCSR_HEXCLEAR, 0);

	return 0;
}

static int db1x_pm_begin(suspend_state_t state)
{
	if (!db1x_pm_wakemsk) {
		printk(KERN_ERR "db1x: no wakeup source activated!\n");
		return -EINVAL;
	}

	return 0;
}

static void db1x_pm_end(void)
{
	/* read and store wakeup source, the clear the register. To
	 * be able to clear it, WAKEMSK must be cleared first.
	 */
	db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);

	alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
	alchemy_wrsys(0, AU1000_SYS_WAKESRC);
}

static const struct platform_suspend_ops db1x_pm_ops = {
	.valid		= suspend_valid_only_mem,
	.begin		= db1x_pm_begin,
	.enter		= db1x_pm_enter,
	.end		= db1x_pm_end,
};

#define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))

static ssize_t db1x_pmattr_show(struct kobject *kobj,
				struct kobj_attribute *attr,
				char *buf)
{
	int idx;

	if (ATTRCMP(timer_timeout))
		return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);

	else if (ATTRCMP(timer))
		return sprintf(buf, "%u\n",
				!!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));

	else if (ATTRCMP(wakesrc))
		return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);

	else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
		 ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
		 ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
		idx = (attr->attr.name)[4] - '0';
		return sprintf(buf, "%d\n",
			!!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));

	} else if (ATTRCMP(wakemsk)) {
		return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
	}

	return -ENOENT;
}

static ssize_t db1x_pmattr_store(struct kobject *kobj,
				 struct kobj_attribute *attr,
				 const char *instr,
				 size_t bytes)
{
	unsigned long l;
	int tmp;

	if (ATTRCMP(timer_timeout)) {
		tmp = kstrtoul(instr, 0, &l);
		if (tmp)
			return tmp;

		db1x_pm_sleep_secs = l;

	} else if (ATTRCMP(timer)) {
		if (instr[0] != '0')
			db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
		else
			db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;

	} else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
		   ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
		   ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
		tmp = (attr->attr.name)[4] - '0';
		if (instr[0] != '0') {
			db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
		} else {
			db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
		}

	} else if (ATTRCMP(wakemsk)) {
		tmp = kstrtoul(instr, 0, &l);
		if (tmp)
			return tmp;

		db1x_pm_wakemsk = l & 0x0000003f;

	} else
		bytes = -ENOENT;

	return bytes;
}

#define ATTR(x)							\
	static struct kobj_attribute x##_attribute =		\
		__ATTR(x, 0664, db1x_pmattr_show,		\
				db1x_pmattr_store);

ATTR(gpio0)		/* GPIO-based wakeup enable */
ATTR(gpio1)
ATTR(gpio2)
ATTR(gpio3)
ATTR(gpio4)
ATTR(gpio5)
ATTR(gpio6)
ATTR(gpio7)
ATTR(timer)		/* TOYMATCH2-based wakeup enable */
ATTR(timer_timeout)	/* timer-based wakeup timeout value, in seconds */
ATTR(wakesrc)		/* contents of SYS_WAKESRC after last wakeup */
ATTR(wakemsk)		/* direct access to SYS_WAKEMSK */

#define ATTR_LIST(x)	& x ## _attribute.attr
static struct attribute *db1x_pmattrs[] = {
	ATTR_LIST(gpio0),
	ATTR_LIST(gpio1),
	ATTR_LIST(gpio2),
	ATTR_LIST(gpio3),
	ATTR_LIST(gpio4),
	ATTR_LIST(gpio5),
	ATTR_LIST(gpio6),
	ATTR_LIST(gpio7),
	ATTR_LIST(timer),
	ATTR_LIST(timer_timeout),
	ATTR_LIST(wakesrc),
	ATTR_LIST(wakemsk),
	NULL,		/* terminator */
};

static struct attribute_group db1x_pmattr_group = {
	.name	= "db1x",
	.attrs	= db1x_pmattrs,
};

/*
 * Initialize suspend interface
 */
static int __init pm_init(void)
{
	/* init TOY to tick at 1Hz if not already done. No need to wait
	 * for confirmation since there's plenty of time from here to
	 * the next suspend cycle.
	 */
	if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767)
		alchemy_wrsys(32767, AU1000_SYS_TOYTRIM);

	db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);

	alchemy_wrsys(0, AU1000_SYS_WAKESRC);
	alchemy_wrsys(0, AU1000_SYS_WAKEMSK);

	suspend_set_ops(&db1x_pm_ops);

	return sysfs_create_group(power_kobj, &db1x_pmattr_group);
}

late_initcall(pm_init);
