static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; if (!(readl_relaxed(gt_base + GT_INT_STATUS) & GT_INT_STATUS_EVENT_FLAG)) return IRQ_NONE; /** * ERRATA 740657( Global Timer can send 2 interrupts for * the same event in single-shot mode) * Workaround: * Either disable single-shot mode. * Or * Modify the Interrupt Handler to avoid the * offending sequence. This is achieved by clearing * the Global Timer flag _after_ having incremented * the Comparator register value to a higher value. */ if (evt->mode == CLOCK_EVT_MODE_ONESHOT) gt_compare_set(ULONG_MAX, 0); writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS); evt->event_handler(evt); return IRQ_HANDLED; }
static void gt_clockevent_set_mode(enum clock_event_mode mode, struct clock_event_device *clk) { unsigned long ctrl; switch (mode) { case CLOCK_EVT_MODE_PERIODIC: gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1); break; case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: ctrl = readl(gt_base + GT_CONTROL); ctrl &= ~(GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE | GT_CONTROL_AUTO_INC); writel(ctrl, gt_base + GT_CONTROL); break; default: break; } }
static int gt_clockevent_set_next_event(unsigned long evt, struct clock_event_device *unused) { gt_compare_set(evt, 0); return 0; }
static int gt_clockevent_set_periodic(struct clock_event_device *evt) { gt_compare_set(DIV_ROUND_CLOSEST(gt_clk_rate, HZ), 1); return 0; }