#include #include #include #include #include #include #include #include #define EPITCR 0x00 #define EPITSR 0x04 #define EPITLR 0x08 #define EPITCMPR 0x0c #define EPITCNR 0x10 #define EPITCR_EN BIT(0) #define EPITCR_ENMOD BIT(1) #define EPITCR_OCIEN BIT(2) #define EPITCR_RLD BIT(3) #define EPITCR_PRESC(x) (((x) & 0xfff) << 4) #define EPITCR_SWR BIT(16) #define EPITCR_IOVW BIT(17) #define EPITCR_DBGEN BIT(18) #define EPITCR_WAITEN BIT(19) #define EPITCR_RES BIT(20) #define EPITCR_STOPEN BIT(21) #define EPITCR_OM_DISCON (0 << 22) #define EPITCR_OM_TOGGLE (1 << 22) #define EPITCR_OM_CLEAR (2 << 22) #define EPITCR_OM_SET (3 << 22) #define EPITCR_CLKSRC_OFF (0 << 24) #define EPITCR_CLKSRC_PERIPHERAL (1 << 24) #define EPITCR_CLKSRC_REF_HIGH (2 << 24) #define EPITCR_CLKSRC_REF_LOW (3 << 24) #define EPITSR_OCIF BIT(0) struct epit_timer { void __iomem *base; int irq; struct clk *clk_per; struct clock_event_device ced; struct irqaction act; }; static inline void epit_irq_disable(struct epit_timer *epittm) { u32 val; val = readl_relaxed(epittm->base + EPITCR); writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR); } static inline void epit_irq_enable(struct epit_timer *epittm) { u32 val; val = readl_relaxed(epittm->base + EPITCR); writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR); } static void epit_irq_acknowledge(struct epit_timer *epittm) { writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR); } static irqreturn_t epit_timer_interrupt(int irq, void *dev_id) { struct epit_timer *epittm = (struct epit_timer *)dev_id; epit_irq_acknowledge(epittm); // ced->event_handler(ced); return IRQ_HANDLED; } static void epit1_timer_init_dt(struct device_node *np) { struct epit_timer *epittm; int ret; int val; unsigned long tcmp; static void __iomem *timer_base; struct clk *clk_per, *clk_ipg; int irq; timer_base = of_iomap(np, 0); WARN_ON(!timer_base); irq = irq_of_parse_and_map(np, 0); clk_ipg = of_clk_get_by_name(np, "ipg"); /* Try osc_per first, and fall back to per otherwise */ clk_per = of_clk_get_by_name(np, "per"); if (IS_ERR(clk_per)) { pr_err("[HWTIMER]i.MX timer: unable to get clk\n"); return; } if (!IS_ERR(clk_ipg)) clk_prepare_enable(clk_ipg); clk_prepare_enable(clk_per); epittm = kzalloc(sizeof(*epittm), GFP_KERNEL); if (!epittm) return; epittm->base = timer_base; epittm->clk_per = clk_per; epittm->irq = irq; //1. Disable the EPIT - set EN=0 in EPIT_EPITCR. //2. Disable EPIT ouput - program OM=00 in the EPIT_EPITCR. //3. Disable EPIT interrupts. val = __raw_readl(epittm->base + EPITCR); val &= ~(EPITCR_OCIEN | EPITCR_OM_SET | EPITCR_EN); __raw_writel(val, epittm->base + EPITCR); //4. Program CLKSRC to desired clock source in EPIT_EPITCR. val = __raw_readl(epittm->base + EPITCR); // val |= EPITCR_CLKSRC_REF_LOW; val |= EPITCR_CLKSRC_REF_HIGH; __raw_writel(val, epittm->base + EPITCR); //5. Clear the EPIT status register (EPIT_EPITSR), that is, write "1" to clear (w1c). __raw_writel(EPITSR_OCIF, epittm->base + EPITSR); //6. Set ENMOD= 1 in the EPIT_EPITCR, to bring the EPIT Counter to defined state //(EPIT_EPITLR value or 0xFFFF_FFFF). val = __raw_readl(epittm->base + EPITCR); val |= (EPITCR_ENMOD | EPITCR_RLD); __raw_writel(val, epittm->base + EPITCR); /* Make irqs happen */ val = request_irq(epittm->irq, epit_timer_interrupt, IRQF_TIMER|IRQF_IRQPOLL, "EPIT1", (void *)epittm); __raw_writel(3750, epittm->base + EPITLR); tcmp = __raw_readl(epittm->base + EPITCNR); __raw_writel(0, epittm->base + EPITCMPR); //7. Enable EPIT - set (EN=1) in the EPIT_EPITCR val = __raw_readl(epittm->base + EPITCR); val |= EPITCR_EN; __raw_writel(val, epittm->base + EPITCR); //8. Enable the EPIT interrupts. epit_irq_enable(epittm); return; } CLOCKSOURCE_OF_DECLARE(epit_timer, "fsl,imx31-epit", epit1_timer_init_dt);