static long sci_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -ENOTTY; int time, period; void __user *argp = (void __user *) arg; int __user *p = argp; switch (cmd) { case WDIOC_GETSUPPORT: ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; break; case WDIOC_GETSTATUS: ret = put_user(0, p); break; case WDIOC_GETBOOTSTATUS: ret = put_user(boot_status, p); break; case WDIOC_GETPRETIMEOUT: ret = put_user(feed_period, p); break; case WDIOC_SETPRETIMEOUT: ret = get_user(period, p); if (ret) break; WDG_LOAD_TIMER_VALUE(period * WDT_FREQ); feed_period = period; break; case WDIOC_KEEPALIVE: WDG_LOAD_TIMER_VALUE(margin * WDT_FREQ); ret = 0; break; case WDIOC_SETTIMEOUT: ret = get_user(time, p); if (ret) break; if (time <= 0 || (WDT_FREQ * (long long) time >= 0xffffffff)) { ret = -EINVAL; break; } WDG_LOAD_TIMER_VALUE(time * WDT_FREQ); margin = time; /*fall through*/ case WDIOC_GETTIMEOUT: ret = put_user(margin, p); break; } return ret; }
/* * This is a hw watchdog starts after init, and fed by a timer started * by the watchdog driver itself. It can also be fed from userland. * The watchdog will be stopped in system suspend, and restarted in * system resume. */ static void watchdog_feeder(unsigned long data) { DEBUG_PRINT(WDT "%s, margin=%d, feed_period=%d\n", __FUNCTION__, margin, feed_period); WDG_LOAD_TIMER_VALUE(margin * WDT_FREQ); mod_timer(&feeder_timer, jiffies + (feed_period * HZ)); }
/* use ana watchdog to wake up */ void pm_debug_set_apwdt(void) { uint32_t cnt = 0; uint32_t ms = 5000; cnt = (ms * WDG_CLK) / 1000; sci_glb_set(INT_IRQ_ENB, BIT(11)); /*enable interface clk*/ sci_adi_set(ANA_AGEN, AGEN_WDG_EN); /*enable work clk*/ sci_adi_set(ANA_RTC_CLK_EN, AGEN_RTC_WDG_EN); sci_adi_raw_write(WDG_LOCK, WDG_UNLOCK_KEY); sci_adi_set(WDG_CTRL, WDG_NEW_VER_EN); WDG_LOAD_TIMER_VALUE(0x80000); WDG_LOAD_TIMER_INT_VALUE(0x40000); sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_INT_EN_BIT| WDG_RST_EN_BIT); sci_adi_raw_write(WDG_LOCK, (uint16_t) (~WDG_UNLOCK_KEY)); sci_adi_set(ANA_REG_INT_EN, BIT(3)); #if 0 do{ udelay(1000); printk("INTC1 mask:0x%08x raw:0x%08x en:0x%08x\n", __raw_readl(INTCV1_IRQ_MSKSTS),__raw_readl(INTCV1_IRQ_RAW), __raw_readl(INTCV1_IRQ_EN)); printk("INT mask:0x%08x raw:0x%08x en:0x%08x ana 0x%08x\n", __raw_readl(INT_IRQ_STS),__raw_readl(INT_IRQ_RAW), __raw_readl(INT_IRQ_ENB), sci_adi_read(ANA_REG_INT_MASK_STATUS)); printk("ANA mask:0x%08x raw:0x%08x en:0x%08x\n", sci_adi_read(ANA_REG_INT_MASK_STATUS), sci_adi_read(ANA_REG_INT_RAW_STATUS), sci_adi_read(ANA_REG_INT_EN)); printk("wdg cnt low 0x%08x high 0x%08x\n", sci_adi_read(WDG_CNT_LOW), sci_adi_read(WDG_CNT_HIGH)); }while(0); #endif }
static ssize_t sci_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { /* TODO: we should have a new reboot reason */ /* sci_adi_raw_write(ANA_RST_STATUS, HWRST_STATUS_NORMAL); */ if (len) WDG_LOAD_TIMER_VALUE(margin * WDT_FREQ); return len; }
static int sci_open(struct inode *inode, struct file *file) { if (test_and_set_bit(1, &wdt_users)) return -EBUSY; /* started the watchdog when it's openned for the 1st time */ if (wdt_state == 0) { /* start the watchdog */ sci_adi_set(ANA_AGEN, AGEN_WDG_EN | AGEN_RTC_ARCH_EN | AGEN_RTC_WDG_EN); sci_adi_raw_write (WDG_LOCK, WDG_UNLOCK_KEY); sci_adi_clr (WDG_CTRL, WDG_INT_EN_BIT); WDG_LOAD_TIMER_VALUE(margin * WDT_FREQ); #ifdef CONFIG_ARCH_SC8825 sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT | WDG_RST_EN_BIT); #else sci_adi_set(WDG_CTRL, WDG_CNT_EN_BIT); #endif mod_timer(&feeder_timer, jiffies + (feed_period * HZ)); wdt_state = 1; } return nonseekable_open(inode, file); }