#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);
|