On Oct 3, 2012, at 5:42 AM, Wang Dongsheng wrote:

> This is only for freescale powerpc platform. The driver provides a way
> to wake up system. Proc interface(/proc/powerpc/wakeup_timer_seconds).
> 
> eg: "echo 5 > /proc/powerpc/wakeup_timer_seconds", 5 seconds
> after the system will be woken up. echo another time into proc interface
> to update the time.
> 
> Signed-off-by: Wang Dongsheng <dongsheng.w...@freescale.com>
> Signed-off-by: Li Yang <le...@freescale.com>
> ---
> arch/powerpc/platforms/Kconfig            |   23 +++
> arch/powerpc/platforms/Makefile           |    1 +
> arch/powerpc/platforms/fsl_timer_wakeup.c |  217 +++++++++++++++++++++++++++++
> 3 files changed, 241 insertions(+)
> create mode 100644 arch/powerpc/platforms/fsl_timer_wakeup.c

Adding the Linux PM list to see if there is some existing support for this on 
other arch's in kernel.

I'm pretty sure /proc/ is NOT where we want this exposed.

- k

> 
> diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
> index b190a6e..7b9232a 100644
> --- a/arch/powerpc/platforms/Kconfig
> +++ b/arch/powerpc/platforms/Kconfig
> @@ -99,6 +99,29 @@ config MPIC_TIMER
>         only tested on fsl chip, but it can potentially support
>         other global timers complying to Open-PIC standard.
> 
> +menuconfig FSL_WAKEUP_SOURCE
> +     bool "Freescale wakeup source"
> +     depends on FSL_SOC && SUSPEND
> +     default n
> +     help
> +       This option enables wakeup source for wake up system
> +       features. This is only for freescale powerpc platform.
> +
> +if FSL_WAKEUP_SOURCE
> +
> +config FSL_TIMER_WAKEUP
> +     tristate "Freescale mpic global timer wakeup event"
> +     default n
> +     help
> +       This is only for freescale powerpc platform. The driver
> +       provides a way to wake up system.
> +       Proc interface(/proc/powerpc/wakeup_timer_seconds).
> +       eg: "echo 5 > /proc/powerpc/wakeup_timer_seconds",
> +       5 seconds after the system will be woken up. echo another
> +       time into proc interface to update the time.
> +
> +endif
> +
> config PPC_EPAPR_HV_PIC
>       bool
>       default n
> diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
> index 879b4a4..8e9a04f 100644
> --- a/arch/powerpc/platforms/Makefile
> +++ b/arch/powerpc/platforms/Makefile
> @@ -2,6 +2,7 @@
> subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
> 
> obj-$(CONFIG_FSL_ULI1575)     += fsl_uli1575.o
> +obj-$(CONFIG_FSL_TIMER_WAKEUP)       += fsl_timer_wakeup.o
> 
> obj-$(CONFIG_PPC_PMAC)                += powermac/
> obj-$(CONFIG_PPC_CHRP)                += chrp/
> diff --git a/arch/powerpc/platforms/fsl_timer_wakeup.c 
> b/arch/powerpc/platforms/fsl_timer_wakeup.c
> new file mode 100644
> index 0000000..f20199f
> --- /dev/null
> +++ b/arch/powerpc/platforms/fsl_timer_wakeup.c
> @@ -0,0 +1,217 @@
> +/*
> + * Copyright 2012 Freescale Semiconductor, Inc.
> + * Wang Dongsheng <dongsheng.w...@freescale.com>
> + * Li Yang <le...@freescale.com>
> + *
> + * This is only for freescale powerpc platform. The driver provides a way
> + * to wake up system. Proc interface(/proc/powerpc/wakeup_timer_seconds).
> + *
> + * eg: "echo 5 > /proc/powerpc/wakeup_timer_seconds", 5 seconds
> + * after the system will be woken up. echo another time into proc interface
> + * to update the time.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published
> + * by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/errno.h>
> +#include <linux/fs.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/sysfs.h>
> +#include <linux/slab.h>
> +#include <linux/mutex.h>
> +#include <linux/pm.h>
> +#include <linux/proc_fs.h>
> +#include <asm/uaccess.h>
> +#include <asm/mpic_timer.h>
> +
> +struct fsl_timer_wakeup {
> +     struct mpic_timer *timer;
> +     struct work_struct free_work;
> +     struct mutex mutex;
> +     struct proc_dir_entry *proc_timer_wakeup;
> +     struct timeval time;
> +};
> +
> +static struct fsl_timer_wakeup *priv;
> +
> +static void timer_event_wakeup_free_work(struct work_struct *ws)
> +{
> +     struct fsl_timer_wakeup *priv =
> +             container_of(ws, struct fsl_timer_wakeup, free_work);
> +
> +     mutex_lock(&priv->mutex);
> +     mpic_free_timer(priv->timer);
> +     priv->timer = NULL;
> +     mutex_unlock(&priv->mutex);
> +}
> +
> +static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
> +{
> +     struct fsl_timer_wakeup *priv = dev_id;
> +
> +     schedule_work(&priv->free_work);
> +
> +     return IRQ_HANDLED;
> +}
> +
> +static ssize_t timer_wakeup_read(struct file *file, char __user *buf,
> +             size_t count, loff_t *offp)
> +{
> +     struct fsl_timer_wakeup *priv;
> +     struct inode *inode = file->f_path.dentry->d_inode;
> +     struct proc_dir_entry *dp;
> +
> +     int ret;
> +     char *kbuf;
> +
> +     dp = PDE(inode);
> +     priv = dp->data;
> +
> +     mutex_lock(&priv->mutex);
> +
> +     if (!priv->timer ||
> +                     (priv->time.tv_sec >= 0 && priv->time.tv_usec >= 0)) {
> +             priv->time.tv_sec = -1;
> +             priv->time.tv_usec = -1;
> +
> +             mutex_unlock(&priv->mutex);
> +
> +             return 0;
> +     }
> +
> +     mpic_get_remain_time(priv->timer, &priv->time);
> +
> +     mutex_unlock(&priv->mutex);
> +
> +     kbuf = kzalloc(count, GFP_KERNEL);
> +     if (!kbuf)
> +             return -ENOMEM;
> +
> +     sprintf(kbuf, "%ld\n%c", priv->time.tv_sec + 1, '\0');
> +
> +     ret = strlen(kbuf);
> +
> +     copy_to_user(buf, kbuf, count);
> +
> +     kfree(kbuf);
> +
> +     return ret;
> +}
> +
> +static ssize_t timer_wakeup_write(struct file *file, const char __user *buf,
> +             size_t count, loff_t *off)
> +{
> +     struct fsl_timer_wakeup *priv;
> +     struct inode *inode = file->f_path.dentry->d_inode;
> +     struct proc_dir_entry *dp;
> +     struct timeval time;
> +     char *kbuf;
> +
> +     dp = PDE(inode);
> +     priv = dp->data;
> +
> +     kbuf = kzalloc(count + 1, GFP_KERNEL);
> +     if (!kbuf)
> +             return -ENOMEM;
> +
> +     if (copy_from_user(kbuf, buf, count)) {
> +             kfree(kbuf);
> +             return -EFAULT;
> +     }
> +
> +     kbuf[count] = '\0';
> +
> +     if (kstrtol(kbuf, 0, &time.tv_sec)) {
> +             kfree(kbuf);
> +             return -EINVAL;
> +     }
> +
> +     kfree(kbuf);
> +
> +     time.tv_usec = 0;
> +
> +     mutex_lock(&priv->mutex);
> +
> +     if (!time.tv_sec) {
> +             if (priv->timer) {
> +                     mpic_free_timer(priv->timer);
> +                     priv->timer = NULL;
> +             }
> +             mutex_unlock(&priv->mutex);
> +
> +             return count;
> +     }
> +
> +     if (priv->timer) {
> +             mpic_free_timer(priv->timer);
> +             priv->timer = NULL;
> +     }
> +
> +     priv->timer = mpic_request_timer(timer_event_interrupt, priv, &time);
> +     if (!priv->timer) {
> +             mutex_unlock(&priv->mutex);
> +
> +             return -EINVAL;
> +     }
> +
> +     mpic_start_timer(priv->timer);
> +
> +     mutex_unlock(&priv->mutex);
> +
> +     return count;
> +}
> +
> +static const struct file_operations timer_wakeup_fops = {
> +     .owner          = THIS_MODULE,
> +     .read           = timer_wakeup_read,
> +     .write          = timer_wakeup_write,
> +     .llseek         = no_llseek,
> +};
> +
> +static int timer_wakeup_init(void)
> +{
> +     struct proc_dir_entry *ent;
> +
> +     priv = kzalloc(sizeof(struct fsl_timer_wakeup), GFP_KERNEL);
> +     if (!priv)
> +             return -ENOMEM;
> +
> +     mutex_init(&priv->mutex);
> +     INIT_WORK(&priv->free_work, timer_event_wakeup_free_work);
> +     priv->time.tv_sec = -1;
> +     priv->time.tv_usec = -1;
> +
> +     ent = proc_create_data("powerpc/wakeup_timer_seconds",
> +                     S_IRUSR | S_IWUSR, NULL, &timer_wakeup_fops, priv);
> +     if (!ent) {
> +             kfree(priv);
> +             return -ENOMEM;
> +     }
> +
> +     priv->proc_timer_wakeup = ent;
> +
> +     return 0;
> +}
> +
> +static void timer_wakeup_exit(void)
> +{
> +     if (priv->timer)
> +             mpic_free_timer(priv->timer);
> +
> +     remove_proc_entry("wakeup_timer_seconds",
> +                     priv->proc_timer_wakeup->parent);
> +
> +     kfree(priv);
> +}
> +
> +module_init(timer_wakeup_init);
> +module_exit(timer_wakeup_exit);
> +
> +MODULE_DESCRIPTION("Freescale mpic global timer event wake-up driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Wang Dongsheng <dongsheng.w...@freescale.com>");
> -- 
> 1.7.9.5

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to