Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * MPIC timer wakeup driver
0004  *
0005  * Copyright 2013 Freescale Semiconductor, Inc.
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include <linux/errno.h>
0011 #include <linux/module.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/device.h>
0014 
0015 #include <asm/mpic_timer.h>
0016 #include <asm/mpic.h>
0017 
0018 struct fsl_mpic_timer_wakeup {
0019     struct mpic_timer *timer;
0020     struct work_struct free_work;
0021 };
0022 
0023 static struct fsl_mpic_timer_wakeup *fsl_wakeup;
0024 static DEFINE_MUTEX(sysfs_lock);
0025 
0026 static void fsl_free_resource(struct work_struct *ws)
0027 {
0028     struct fsl_mpic_timer_wakeup *wakeup =
0029         container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
0030 
0031     mutex_lock(&sysfs_lock);
0032 
0033     if (wakeup->timer) {
0034         disable_irq_wake(wakeup->timer->irq);
0035         mpic_free_timer(wakeup->timer);
0036     }
0037 
0038     wakeup->timer = NULL;
0039     mutex_unlock(&sysfs_lock);
0040 }
0041 
0042 static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
0043 {
0044     struct fsl_mpic_timer_wakeup *wakeup = dev_id;
0045 
0046     schedule_work(&wakeup->free_work);
0047 
0048     return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
0049 }
0050 
0051 static ssize_t fsl_timer_wakeup_show(struct device *dev,
0052                 struct device_attribute *attr,
0053                 char *buf)
0054 {
0055     time64_t interval = 0;
0056 
0057     mutex_lock(&sysfs_lock);
0058     if (fsl_wakeup->timer) {
0059         mpic_get_remain_time(fsl_wakeup->timer, &interval);
0060         interval++;
0061     }
0062     mutex_unlock(&sysfs_lock);
0063 
0064     return sprintf(buf, "%lld\n", interval);
0065 }
0066 
0067 static ssize_t fsl_timer_wakeup_store(struct device *dev,
0068                 struct device_attribute *attr,
0069                 const char *buf,
0070                 size_t count)
0071 {
0072     time64_t interval;
0073     int ret;
0074 
0075     if (kstrtoll(buf, 0, &interval))
0076         return -EINVAL;
0077 
0078     mutex_lock(&sysfs_lock);
0079 
0080     if (fsl_wakeup->timer) {
0081         disable_irq_wake(fsl_wakeup->timer->irq);
0082         mpic_free_timer(fsl_wakeup->timer);
0083         fsl_wakeup->timer = NULL;
0084     }
0085 
0086     if (!interval) {
0087         mutex_unlock(&sysfs_lock);
0088         return count;
0089     }
0090 
0091     fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
0092                         fsl_wakeup, interval);
0093     if (!fsl_wakeup->timer) {
0094         mutex_unlock(&sysfs_lock);
0095         return -EINVAL;
0096     }
0097 
0098     ret = enable_irq_wake(fsl_wakeup->timer->irq);
0099     if (ret) {
0100         mpic_free_timer(fsl_wakeup->timer);
0101         fsl_wakeup->timer = NULL;
0102         mutex_unlock(&sysfs_lock);
0103 
0104         return ret;
0105     }
0106 
0107     mpic_start_timer(fsl_wakeup->timer);
0108 
0109     mutex_unlock(&sysfs_lock);
0110 
0111     return count;
0112 }
0113 
0114 static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
0115             fsl_timer_wakeup_show, fsl_timer_wakeup_store);
0116 
0117 static int __init fsl_wakeup_sys_init(void)
0118 {
0119     int ret;
0120 
0121     fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
0122     if (!fsl_wakeup)
0123         return -ENOMEM;
0124 
0125     INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
0126 
0127     ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
0128     if (ret)
0129         kfree(fsl_wakeup);
0130 
0131     return ret;
0132 }
0133 
0134 static void __exit fsl_wakeup_sys_exit(void)
0135 {
0136     device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
0137 
0138     mutex_lock(&sysfs_lock);
0139 
0140     if (fsl_wakeup->timer) {
0141         disable_irq_wake(fsl_wakeup->timer->irq);
0142         mpic_free_timer(fsl_wakeup->timer);
0143     }
0144 
0145     kfree(fsl_wakeup);
0146 
0147     mutex_unlock(&sysfs_lock);
0148 }
0149 
0150 module_init(fsl_wakeup_sys_init);
0151 module_exit(fsl_wakeup_sys_exit);
0152 
0153 MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
0154 MODULE_LICENSE("GPL v2");
0155 MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");