162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com 462306a36Sopenharmony_ci * All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2017 Google, Inc. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/clk.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/clockchips.h> 1762306a36Sopenharmony_ci#include <linux/of_irq.h> 1862306a36Sopenharmony_ci#include <linux/of_address.h> 1962306a36Sopenharmony_ci#include "timer-of.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* Timers registers */ 2262306a36Sopenharmony_ci#define NPCM7XX_REG_TCSR0 0x0 /* Timer 0 Control and Status Register */ 2362306a36Sopenharmony_ci#define NPCM7XX_REG_TICR0 0x8 /* Timer 0 Initial Count Register */ 2462306a36Sopenharmony_ci#define NPCM7XX_REG_TCSR1 0x4 /* Timer 1 Control and Status Register */ 2562306a36Sopenharmony_ci#define NPCM7XX_REG_TICR1 0xc /* Timer 1 Initial Count Register */ 2662306a36Sopenharmony_ci#define NPCM7XX_REG_TDR1 0x14 /* Timer 1 Data Register */ 2762306a36Sopenharmony_ci#define NPCM7XX_REG_TISR 0x18 /* Timer Interrupt Status Register */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* Timers control */ 3062306a36Sopenharmony_ci#define NPCM7XX_Tx_RESETINT 0x1f 3162306a36Sopenharmony_ci#define NPCM7XX_Tx_PERIOD BIT(27) 3262306a36Sopenharmony_ci#define NPCM7XX_Tx_INTEN BIT(29) 3362306a36Sopenharmony_ci#define NPCM7XX_Tx_COUNTEN BIT(30) 3462306a36Sopenharmony_ci#define NPCM7XX_Tx_ONESHOT 0x0 3562306a36Sopenharmony_ci#define NPCM7XX_Tx_OPER GENMASK(28, 27) 3662306a36Sopenharmony_ci#define NPCM7XX_Tx_MIN_PRESCALE 0x1 3762306a36Sopenharmony_ci#define NPCM7XX_Tx_TDR_MASK_BITS 24 3862306a36Sopenharmony_ci#define NPCM7XX_Tx_MAX_CNT 0xFFFFFF 3962306a36Sopenharmony_ci#define NPCM7XX_T0_CLR_INT 0x1 4062306a36Sopenharmony_ci#define NPCM7XX_Tx_CLR_CSR 0x0 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Timers operating mode */ 4362306a36Sopenharmony_ci#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \ 4462306a36Sopenharmony_ci NPCM7XX_Tx_INTEN | \ 4562306a36Sopenharmony_ci NPCM7XX_Tx_MIN_PRESCALE) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \ 4862306a36Sopenharmony_ci NPCM7XX_Tx_INTEN | \ 4962306a36Sopenharmony_ci NPCM7XX_Tx_MIN_PRESCALE) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \ 5262306a36Sopenharmony_ci NPCM7XX_Tx_MIN_PRESCALE) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic int npcm7xx_timer_resume(struct clock_event_device *evt) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 5962306a36Sopenharmony_ci u32 val; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 6262306a36Sopenharmony_ci val |= NPCM7XX_Tx_COUNTEN; 6362306a36Sopenharmony_ci writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic int npcm7xx_timer_shutdown(struct clock_event_device *evt) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 7162306a36Sopenharmony_ci u32 val; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 7462306a36Sopenharmony_ci val &= ~NPCM7XX_Tx_COUNTEN; 7562306a36Sopenharmony_ci writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int npcm7xx_timer_oneshot(struct clock_event_device *evt) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 8362306a36Sopenharmony_ci u32 val; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 8662306a36Sopenharmony_ci val &= ~NPCM7XX_Tx_OPER; 8762306a36Sopenharmony_ci val |= NPCM7XX_START_ONESHOT_Tx; 8862306a36Sopenharmony_ci writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int npcm7xx_timer_periodic(struct clock_event_device *evt) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 9662306a36Sopenharmony_ci u32 val; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 10162306a36Sopenharmony_ci val &= ~NPCM7XX_Tx_OPER; 10262306a36Sopenharmony_ci val |= NPCM7XX_START_PERIODIC_Tx; 10362306a36Sopenharmony_ci writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int npcm7xx_clockevent_set_next_event(unsigned long evt, 10962306a36Sopenharmony_ci struct clock_event_device *clk) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct timer_of *to = to_timer_of(clk); 11262306a36Sopenharmony_ci u32 val; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0); 11562306a36Sopenharmony_ci val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0); 11662306a36Sopenharmony_ci val |= NPCM7XX_START_Tx; 11762306a36Sopenharmony_ci writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct clock_event_device *evt = (struct clock_event_device *)dev_id; 12562306a36Sopenharmony_ci struct timer_of *to = to_timer_of(evt); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci evt->event_handler(evt); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return IRQ_HANDLED; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic struct timer_of npcm7xx_to = { 13562306a36Sopenharmony_ci .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci .clkevt = { 13862306a36Sopenharmony_ci .name = "npcm7xx-timer0", 13962306a36Sopenharmony_ci .features = CLOCK_EVT_FEAT_PERIODIC | 14062306a36Sopenharmony_ci CLOCK_EVT_FEAT_ONESHOT, 14162306a36Sopenharmony_ci .set_next_event = npcm7xx_clockevent_set_next_event, 14262306a36Sopenharmony_ci .set_state_shutdown = npcm7xx_timer_shutdown, 14362306a36Sopenharmony_ci .set_state_periodic = npcm7xx_timer_periodic, 14462306a36Sopenharmony_ci .set_state_oneshot = npcm7xx_timer_oneshot, 14562306a36Sopenharmony_ci .tick_resume = npcm7xx_timer_resume, 14662306a36Sopenharmony_ci .rating = 300, 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci .of_irq = { 15062306a36Sopenharmony_ci .handler = npcm7xx_timer0_interrupt, 15162306a36Sopenharmony_ci .flags = IRQF_TIMER | IRQF_IRQPOLL, 15262306a36Sopenharmony_ci }, 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic void __init npcm7xx_clockevents_init(void) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci writel(NPCM7XX_DEFAULT_CSR, 15862306a36Sopenharmony_ci timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci writel(NPCM7XX_Tx_RESETINT, 16162306a36Sopenharmony_ci timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci npcm7xx_to.clkevt.cpumask = cpumask_of(0); 16462306a36Sopenharmony_ci clockevents_config_and_register(&npcm7xx_to.clkevt, 16562306a36Sopenharmony_ci timer_of_rate(&npcm7xx_to), 16662306a36Sopenharmony_ci 0x1, NPCM7XX_Tx_MAX_CNT); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void __init npcm7xx_clocksource_init(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci u32 val; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci writel(NPCM7XX_DEFAULT_CSR, 17462306a36Sopenharmony_ci timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 17562306a36Sopenharmony_ci writel(NPCM7XX_Tx_MAX_CNT, 17662306a36Sopenharmony_ci timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 17962306a36Sopenharmony_ci val |= NPCM7XX_START_Tx; 18062306a36Sopenharmony_ci writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci clocksource_mmio_init(timer_of_base(&npcm7xx_to) + 18362306a36Sopenharmony_ci NPCM7XX_REG_TDR1, 18462306a36Sopenharmony_ci "npcm7xx-timer1", timer_of_rate(&npcm7xx_to), 18562306a36Sopenharmony_ci 200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS, 18662306a36Sopenharmony_ci clocksource_mmio_readl_down); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int __init npcm7xx_timer_init(struct device_node *np) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct clk *clk; 19262306a36Sopenharmony_ci int ret; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci ret = timer_of_init(np, &npcm7xx_to); 19562306a36Sopenharmony_ci if (ret) 19662306a36Sopenharmony_ci return ret; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Clock input is divided by PRESCALE + 1 before it is fed */ 19962306a36Sopenharmony_ci /* to the counter */ 20062306a36Sopenharmony_ci npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate / 20162306a36Sopenharmony_ci (NPCM7XX_Tx_MIN_PRESCALE + 1); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Enable the clock for timer1, if it exists */ 20462306a36Sopenharmony_ci clk = of_clk_get(np, 1); 20562306a36Sopenharmony_ci if (clk) { 20662306a36Sopenharmony_ci if (!IS_ERR(clk)) 20762306a36Sopenharmony_ci clk_prepare_enable(clk); 20862306a36Sopenharmony_ci else 20962306a36Sopenharmony_ci pr_warn("%pOF: Failed to get clock for timer1: %pe", np, clk); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci npcm7xx_clocksource_init(); 21362306a36Sopenharmony_ci npcm7xx_clockevents_init(); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ", 21662306a36Sopenharmony_ci timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to)); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciTIMER_OF_DECLARE(wpcm450, "nuvoton,wpcm450-timer", npcm7xx_timer_init); 22262306a36Sopenharmony_ciTIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init); 22362306a36Sopenharmony_ci 224