123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com
- * All rights reserved.
- *
- * Copyright 2017 Google, Inc.
- */
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/err.h>
- #include <linux/clk.h>
- #include <linux/io.h>
- #include <linux/clockchips.h>
- #include <linux/of_irq.h>
- #include <linux/of_address.h>
- #include "timer-of.h"
- /* Timers registers */
- #define NPCM7XX_REG_TCSR0 0x0 /* Timer 0 Control and Status Register */
- #define NPCM7XX_REG_TICR0 0x8 /* Timer 0 Initial Count Register */
- #define NPCM7XX_REG_TCSR1 0x4 /* Timer 1 Control and Status Register */
- #define NPCM7XX_REG_TICR1 0xc /* Timer 1 Initial Count Register */
- #define NPCM7XX_REG_TDR1 0x14 /* Timer 1 Data Register */
- #define NPCM7XX_REG_TISR 0x18 /* Timer Interrupt Status Register */
- /* Timers control */
- #define NPCM7XX_Tx_RESETINT 0x1f
- #define NPCM7XX_Tx_PERIOD BIT(27)
- #define NPCM7XX_Tx_INTEN BIT(29)
- #define NPCM7XX_Tx_COUNTEN BIT(30)
- #define NPCM7XX_Tx_ONESHOT 0x0
- #define NPCM7XX_Tx_OPER GENMASK(3, 27)
- #define NPCM7XX_Tx_MIN_PRESCALE 0x1
- #define NPCM7XX_Tx_TDR_MASK_BITS 24
- #define NPCM7XX_Tx_MAX_CNT 0xFFFFFF
- #define NPCM7XX_T0_CLR_INT 0x1
- #define NPCM7XX_Tx_CLR_CSR 0x0
- /* Timers operating mode */
- #define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \
- NPCM7XX_Tx_INTEN | \
- NPCM7XX_Tx_MIN_PRESCALE)
- #define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \
- NPCM7XX_Tx_INTEN | \
- NPCM7XX_Tx_MIN_PRESCALE)
- #define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \
- NPCM7XX_Tx_MIN_PRESCALE)
- #define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE)
- static int npcm7xx_timer_resume(struct clock_event_device *evt)
- {
- struct timer_of *to = to_timer_of(evt);
- u32 val;
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val |= NPCM7XX_Tx_COUNTEN;
- writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
- return 0;
- }
- static int npcm7xx_timer_shutdown(struct clock_event_device *evt)
- {
- struct timer_of *to = to_timer_of(evt);
- u32 val;
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val &= ~NPCM7XX_Tx_COUNTEN;
- writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
- return 0;
- }
- static int npcm7xx_timer_oneshot(struct clock_event_device *evt)
- {
- struct timer_of *to = to_timer_of(evt);
- u32 val;
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val &= ~NPCM7XX_Tx_OPER;
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val |= NPCM7XX_START_ONESHOT_Tx;
- writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
- return 0;
- }
- static int npcm7xx_timer_periodic(struct clock_event_device *evt)
- {
- struct timer_of *to = to_timer_of(evt);
- u32 val;
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val &= ~NPCM7XX_Tx_OPER;
- writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);
- val |= NPCM7XX_START_PERIODIC_Tx;
- writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
- return 0;
- }
- static int npcm7xx_clockevent_set_next_event(unsigned long evt,
- struct clock_event_device *clk)
- {
- struct timer_of *to = to_timer_of(clk);
- u32 val;
- writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);
- val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
- val |= NPCM7XX_START_Tx;
- writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
- return 0;
- }
- static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)
- {
- struct clock_event_device *evt = (struct clock_event_device *)dev_id;
- struct timer_of *to = to_timer_of(evt);
- writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
- static struct timer_of npcm7xx_to = {
- .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
- .clkevt = {
- .name = "npcm7xx-timer0",
- .features = CLOCK_EVT_FEAT_PERIODIC |
- CLOCK_EVT_FEAT_ONESHOT,
- .set_next_event = npcm7xx_clockevent_set_next_event,
- .set_state_shutdown = npcm7xx_timer_shutdown,
- .set_state_periodic = npcm7xx_timer_periodic,
- .set_state_oneshot = npcm7xx_timer_oneshot,
- .tick_resume = npcm7xx_timer_resume,
- .rating = 300,
- },
- .of_irq = {
- .handler = npcm7xx_timer0_interrupt,
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- },
- };
- static void __init npcm7xx_clockevents_init(void)
- {
- writel(NPCM7XX_DEFAULT_CSR,
- timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);
- writel(NPCM7XX_Tx_RESETINT,
- timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);
- npcm7xx_to.clkevt.cpumask = cpumask_of(0);
- clockevents_config_and_register(&npcm7xx_to.clkevt,
- timer_of_rate(&npcm7xx_to),
- 0x1, NPCM7XX_Tx_MAX_CNT);
- }
- static void __init npcm7xx_clocksource_init(void)
- {
- u32 val;
- writel(NPCM7XX_DEFAULT_CSR,
- timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
- writel(NPCM7XX_Tx_MAX_CNT,
- timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);
- val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
- val |= NPCM7XX_START_Tx;
- writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
- clocksource_mmio_init(timer_of_base(&npcm7xx_to) +
- NPCM7XX_REG_TDR1,
- "npcm7xx-timer1", timer_of_rate(&npcm7xx_to),
- 200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,
- clocksource_mmio_readl_down);
- }
- static int __init npcm7xx_timer_init(struct device_node *np)
- {
- int ret;
- ret = timer_of_init(np, &npcm7xx_to);
- if (ret)
- return ret;
- /* Clock input is divided by PRESCALE + 1 before it is fed */
- /* to the counter */
- npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
- (NPCM7XX_Tx_MIN_PRESCALE + 1);
- npcm7xx_clocksource_init();
- npcm7xx_clockevents_init();
- pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",
- timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));
- return 0;
- }
- TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
|