Path: blob/master/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
26424 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* MPIC timer wakeup driver3*4* Copyright 2013 Freescale Semiconductor, Inc.5*/67#include <linux/kernel.h>8#include <linux/slab.h>9#include <linux/errno.h>10#include <linux/module.h>11#include <linux/interrupt.h>12#include <linux/device.h>1314#include <asm/mpic_timer.h>15#include <asm/mpic.h>1617struct fsl_mpic_timer_wakeup {18struct mpic_timer *timer;19struct work_struct free_work;20};2122static struct fsl_mpic_timer_wakeup *fsl_wakeup;23static DEFINE_MUTEX(sysfs_lock);2425static void fsl_free_resource(struct work_struct *ws)26{27struct fsl_mpic_timer_wakeup *wakeup =28container_of(ws, struct fsl_mpic_timer_wakeup, free_work);2930mutex_lock(&sysfs_lock);3132if (wakeup->timer) {33disable_irq_wake(wakeup->timer->irq);34mpic_free_timer(wakeup->timer);35}3637wakeup->timer = NULL;38mutex_unlock(&sysfs_lock);39}4041static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)42{43struct fsl_mpic_timer_wakeup *wakeup = dev_id;4445schedule_work(&wakeup->free_work);4647return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;48}4950static ssize_t fsl_timer_wakeup_show(struct device *dev,51struct device_attribute *attr,52char *buf)53{54time64_t interval = 0;5556mutex_lock(&sysfs_lock);57if (fsl_wakeup->timer) {58mpic_get_remain_time(fsl_wakeup->timer, &interval);59interval++;60}61mutex_unlock(&sysfs_lock);6263return sprintf(buf, "%lld\n", interval);64}6566static ssize_t fsl_timer_wakeup_store(struct device *dev,67struct device_attribute *attr,68const char *buf,69size_t count)70{71time64_t interval;72int ret;7374if (kstrtoll(buf, 0, &interval))75return -EINVAL;7677guard(mutex)(&sysfs_lock);7879if (fsl_wakeup->timer) {80disable_irq_wake(fsl_wakeup->timer->irq);81mpic_free_timer(fsl_wakeup->timer);82fsl_wakeup->timer = NULL;83}8485if (!interval)86return count;8788fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,89fsl_wakeup, interval);90if (!fsl_wakeup->timer)91return -EINVAL;9293ret = enable_irq_wake(fsl_wakeup->timer->irq);94if (ret) {95mpic_free_timer(fsl_wakeup->timer);96fsl_wakeup->timer = NULL;97return ret;98}99100mpic_start_timer(fsl_wakeup->timer);101102return count;103}104105static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,106fsl_timer_wakeup_show, fsl_timer_wakeup_store);107108static int __init fsl_wakeup_sys_init(void)109{110struct device *dev_root;111int ret = -EINVAL;112113fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);114if (!fsl_wakeup)115return -ENOMEM;116117INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);118119dev_root = bus_get_dev_root(&mpic_subsys);120if (dev_root) {121ret = device_create_file(dev_root, &mpic_attributes);122put_device(dev_root);123if (ret)124kfree(fsl_wakeup);125}126127return ret;128}129130static void __exit fsl_wakeup_sys_exit(void)131{132struct device *dev_root;133134dev_root = bus_get_dev_root(&mpic_subsys);135if (dev_root) {136device_remove_file(dev_root, &mpic_attributes);137put_device(dev_root);138}139140mutex_lock(&sysfs_lock);141142if (fsl_wakeup->timer) {143disable_irq_wake(fsl_wakeup->timer->irq);144mpic_free_timer(fsl_wakeup->timer);145}146147kfree(fsl_wakeup);148149mutex_unlock(&sysfs_lock);150}151152module_init(fsl_wakeup_sys_init);153module_exit(fsl_wakeup_sys_exit);154155MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");156MODULE_LICENSE("GPL v2");157MODULE_AUTHOR("Wang Dongsheng <[email protected]>");158159160