#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <asm/io.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zl");
#define WDT_MAGIC 'Y'
#define WDT_ON _IOW(WDT_MAGIC, 0x00, int)
#define WDT_OFF _IOW(WDT_MAGIC, 0x01, int)
#define WDT_MODE _IOW(WDT_MAGIC, 0x02, int)
#define WDT_FEED _IOW(WDT_MAGIC, 0x03, int)
struct watch_dog {
unsigned long virt,phys;
unsigned long wdtcon;
unsigned long wdtdat;
unsigned long wdtcnt;
char name[1024];
int reset_mode;
int irq;
void (*on)(struct watch_dog *);
void (*off)(struct watch_dog *);
void (*mode)(struct watch_dog *, int);
void (*feed)(struct watch_dog *);
//----------------
dev_t no;
struct cdev dev;
};
void mywdt_on(struct watch_dog* mywdt)
{
iowrite32(ioread32(mywdt->wdtcon) | (1 << 5), mywdt->wdtcon);
}
void mywdt_off(struct watch_dog* mywdt)
{
iowrite32(ioread32(mywdt->wdtcon) & ~(1 << 5), mywdt->wdtcon);
}
void mywdt_mode(struct watch_dog* mywdt, int mymode)
{
unsigned long tmp;
mywdt->reset_mode = mymode;
tmp = ioread32(mywdt->wdtcon);
if(mywdt->wdtcon)
{
iowrite32((tmp & ~(1 << 2)) | 1, mywdt->wdtcon);
}
else
{
iowrite32((tmp & ~1) | (1 << 2), mywdt->wdtcon);
}
}
void mywdt_feed(struct watch_dog* mywdt)
{
iowrite32(0x8000, mywdt->wdtcnt);
}
irqreturn_t mywdt_handle(int irq, struct watch_dog *mywdt)
{
printk("wdt timer....\n");
return IRQ_HANDLED;
}
int init_watch_dog(struct watch_dog *mywdt, const char *name )
{
int ret = 0;
strcpy(mywdt->name, name);
mywdt->phys = 0x53000000;
mywdt->irq = IRQ_S3C2440_WDT;
mywdt->reset_mode = 0;
ret = request_mem_region(mywdt->phys, SZ_4K, mywdt->name );
if ((void *)ret == NULL) {
ret = -EBUSY;
goto err0;
}
ret = 0;
mywdt->virt = ioremap(mywdt->phys, SZ_4K);
if (mywdt->virt == NULL) {
ret = -EBUSY;
goto err1;
}
mywdt->wdtcon = mywdt->virt + 0x00;
mywdt->wdtdat = mywdt->virt + 0x04;
mywdt->wdtcnt = mywdt->virt + 0x08;
if (ret) {
goto err2;
}
mywdt->on = mywdt_on;
mywdt->off = mywdt_off;
mywdt->feed = mywdt_feed;
mywdt->mode = mywdt_mode;
iowrite32( 0x8004, mywdt->wdtcon);
return ret;
err2:
iounmap(mywdt->virt);
err1:
release_mem_region(mywdt->phys, SZ_4K);
err0:
return ret;
}
void destroy_watch_dog(struct watch_dog *mywdt)
{
iowrite32( 0x0, mywdt->wdtcon);
iounmap(mywdt->virt);
release_mem_region(mywdt->phys, SZ_4K);
free_irq(mywdt->irq, mywdt);
}
//----------------------------------------
int mywdt_ioctl(struct inode *no, struct file *fp, unsigned long cmd, unsigned long arg)
{
int ret = 0;
struct watch_dog *mywdt = container_of(no->i_cdev, struct watch_dog, dev);
switch(cmd) {
case WDT_ON:
mywdt->on(mywdt);
break;
case WDT_OFF:
mywdt->off(mywdt);
break;
case WDT_MODE:
mywdt->mode(mywdt, arg);
break;
case WDT_FEED:
mywdt->feed(mywdt);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
struct watch_dog s3c2440_wdt;
struct file_operations s3c2440_wdt_ops = {
.ioctl = mywdt_ioctl,
};
int test_init(void)
{
int ret = 0;
ret = init_watch_dog(&s3c2440_wdt, "s3c2440 watch dog");
if (ret) {
goto err0;
}
s3c2440_wdt.no = MKDEV(52, 0);
ret = register_chrdev_region(s3c2440_wdt.no, 1, s3c2440_wdt.name);
if (ret) {
goto err1;
}
cdev_init(&s3c2440_wdt.dev, &s3c2440_wdt_ops);
cdev_add(&s3c2440_wdt.dev, s3c2440_wdt.no, 1);
return ret;
err1:
destroy_watch_dog(&s3c2440_wdt);
err0:
return ret;
}
void test_exit(void)
{
destroy_watch_dog(&s3c2440_wdt);
cdev_del(&s3c2440_wdt.dev);
unregister_chrdev_region(s3c2440_wdt.no, 1);
}
module_init(test_init);
module_exit(test_exit);
|