irqreturn_t ath_wdt_isr(int cpl, void *dev_id) { unsigned delay; extern int ath_gpio_in_val(int); #define UDELAY_COUNT 4000 wddbg("%s: invoked\n", __func__); for (delay = UDELAY_COUNT; delay; delay--) { if (ath_gpio_in_val(ATH_GPIO_RESET)) { break; } udelay(1000); } wddbg("%s: %d", __func__, delay); if (!delay) { wake_up(&wdt->wq); } else { extern void ath_restart(char *); ath_restart(NULL); } return IRQ_HANDLED; }
static int ar7240wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; wddbg("%s: called\n", __func__); switch(cmd) { case FACTORY_RESET: wddbg("%s: intr action\n", __func__); #ifndef CONFIG_MACH_HORNET if ((ret = request_irq( AR7240_MISC_IRQ_WATCHDOG, ar7240_wdt_isr, 0, "Watchdog Timer", wdt))) { wddbg("%s: request_irq %d\n", __func__, ret); return ret; } ar7240_set_wd_timer_action(AR7240_WD_ACT_GP_INTR); sleep_on(&wdt->wq); free_irq(AR7240_MISC_IRQ_WATCHDOG, wdt); #endif break; default: ret = -EINVAL; } return ret; }
FAR void *watchdog_register(FAR const char *path, FAR struct watchdog_lowerhalf_s *lower) { FAR struct watchdog_upperhalf_s *upper; int ret; DEBUGASSERT(path && lower); wdvdbg("Entry: path=%s\n", path); /* Allocate the upper-half data structure */ upper = (FAR struct watchdog_upperhalf_s *) kzalloc(sizeof(struct watchdog_upperhalf_s)); if (!upper) { wddbg("Upper half allocation failed\n"); goto errout; } /* Initialize the watchdog timer device structure (it was already zeroed * by kzalloc()). */ sem_init(&upper->exclsem, 0, 1); upper->lower = lower; /* Copy the registration path */ upper->path = strdup(path); if (!upper->path) { wddbg("Path allocation failed\n"); goto errout_with_upper; } /* Register the watchdog timer device */ ret = register_driver(path, &g_wdogops, 0666, upper); if (ret < 0) { wddbg("register_driver failed: %d\n", ret); goto errout_with_path; } return (FAR void *)upper; errout_with_path: kfree(upper->path); errout_with_upper: sem_destroy(&upper->exclsem); kfree(upper); errout: return NULL; }
static ssize_t ar7240wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { int i; char c; wddbg("%s: called\n", __func__); for (i = 0; i != count; i++) { if (get_user(c, buf + i)) { return -EFAULT; } if (c == 'V') { wdt->can_close = 1; break; } } if (i) { ar7240_set_wd_timer(wdt->tmo); return 1; } return 0; }
static ssize_t ar7240wdt_read(struct file *file, char *buf, size_t count, loff_t *ppos) { wddbg("%s: called\n", __func__); return -ENOTSUPP; }
static int ar7240wdt_open(struct inode *inode, struct file *file) { wddbg("%s: called\n", __func__); if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) { return -ENODEV; } if (wdt->open) { return -EBUSY; } wdt->open = 1; wdt->tmo = AR7240_DEFAULT_WD_TMO; wdt->action = AR7240_WD_ACT_NONE; wdt->can_close = 0; init_waitqueue_head(&wdt->wq); ar7240_set_wd_timer(wdt->tmo); #ifndef CONFIG_MACH_HORNET ar7240_set_wd_timer_action(AR7240_WD_ACT_NONE); #endif return nonseekable_open(inode, file); }
/* Set the timeout value in the watchdog register */ void ath_set_wd_timer(uint32_t usec /* micro seconds */) { #if defined(CONFIG_MACH_QCA956x) uint32_t vTmpusec = 0; uint32_t vCnt = 0; #endif #if defined(CONFIG_MACH_AR934x) || defined(CONFIG_MACH_QCA955x) || \ defined(CONFIG_MACH_QCA953x) || defined(CONFIG_MACH_QCA956x) usec = usec * (ath_ref_freq / USEC_PER_SEC); #else usec = usec * (ath_ahb_freq / USEC_PER_SEC); #endif wddbg("%s: 0x%08x\n", __func__, usec); #if defined(CONFIG_MACH_QCA956x) //EV[131847], wait WDT timer write in( wait limit time ) vTmpusec = ath_reg_rd(ATH_WATCHDOG_TMR); ath_reg_wr(ATH_WATCHDOG_TMR, usec); while(ath_reg_rd(ATH_WATCHDOG_TMR) <= vTmpusec) { vCnt++; if(vCnt >= 100) { printk("%s: Write WDT Timer fail !\n",__func__); break; } } #else ath_reg_wr(ATH_WATCHDOG_TMR, usec); #endif }
static int athwdt_close(struct inode *inode, struct file *file) { wddbg("%s: called\n", __func__); if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) { return -ENODEV; } if (!wdt->can_close) { wddbg("%s: clearing action\n", __func__); ath_set_wd_timer_action(ATH_WD_ACT_NONE); } else { wddbg("%s: not clearing action\n", __func__); } wdt->open = 0; return 0; }
/* Set the timeout value in the watchdog register */ static inline void ar7240_set_wd_timer(uint32_t usec /* micro seconds */) { usec = usec * (wdt->clk_freq / USEC_PER_SEC); wddbg("%s: 0x%08x\n", __func__, usec); ar7240_reg_wr(AR7240_WATCHDOG_TMR, usec); }
static int ar7240wdt_close(struct inode *inode, struct file *file) { wddbg("%s: called\n", __func__); if (MINOR(inode->i_rdev) != WATCHDOG_MINOR) { return -ENODEV; } if (!wdt->can_close) { wddbg("%s: clearing action\n", __func__); #ifndef CONFIG_MACH_HORNET ar7240_set_wd_timer_action(AR7240_WD_ACT_NONE); #endif } else { wddbg("%s: not clearing action\n", __func__); } wdt->open = 0; return 0; }
irqreturn_t ar7240_wdt_isr(int cpl, void *dev_id, struct pt_regs *regs) { unsigned delay; extern int ar7240_gpio_in_val(int); #define UDELAY_COUNT 4000 wddbg("%s: invoked\n", __func__); #ifdef CONFIG_MACH_HORNET local_irq_disable(); #endif for (delay = UDELAY_COUNT; delay; delay--) { if (ar7240_gpio_in_val(AR7240_GPIO_RESET)) { break; } udelay(1000); } wddbg("%s: %d", __func__, delay); if (!delay) { #ifdef CONFIG_MACH_HORNET #ifdef AP_WATCHDOG_RESET_DISABLE ar7240_set_wd_timer(wdt->tmo); ar7240_set_wd_timer_action(AR7240_WD_ACT_RESET); udelay(100); #endif ar7240_set_wd_timer(0); #else wake_up(&wdt->wq); #endif } else { #ifdef CONFIG_MACH_HORNET local_irq_enable(); #else extern void ar7240_restart(char *); ar7240_restart(NULL); #endif } return IRQ_HANDLED; }
static inline int ar7240_set_wd_timer_action(uint32_t val) { if (val & ~AR7240_WD_ACT_MASK) { return EINVAL; } wdt->action = val; wddbg("%s: 0x%08x\n", __func__, val); /* * bits : 31 30 - 2 0-1 * access: RO rsvd Action * * Since bit 31 is read only and rest of the bits * are zero, don't have to do a read-modify-write */ ar7240_reg_wr(AR7240_WATCHDOG_TMR_CONTROL, val); return 0; }
void ar7240wdt_init(void) { int ret; extern void ar7240_gpio_config_input(int); printk("%s: Registering WDT ", __func__); if ((ret = misc_register(&ar7240wdt_miscdev))) { printk("failed %d\n", ret); return; } else { printk("success\n"); } #ifdef CONFIG_WASP_SUPPORT wdt->clk_freq = ath_ref_clk_freq; #else wdt->clk_freq = ar7240_ahb_freq; #endif #ifdef CONFIG_MACH_HORNET wdt->tmo = AR7240_DEFAULT_WD_TMO; ar7240_set_wd_timer(wdt->tmo * 6); ar7240_set_wd_timer_action(AR7240_WD_ACT_RESET); mod_timer(&wd_timer, AR7240_DEFAULT_MOD_TMO); if (request_irq( AR7240_GPIO_IRQn(AR7240_GPIO_RESET), ar7240_wdt_isr, 0, "Watchdog Reset", wdt)) { wddbg("%s: request_irq %d\n", __func__, ret); } #endif ar7240_gpio_config_input(AR7240_GPIO_RESET); }