-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/…
…linux/kernel/git/tip/tip Pull missed timer updates from Thomas Gleixner: "This is a branch which got forgotten during the merge window, but it contains only fixes and hardware enablement. No fundamental changes. - Various fixes for the imx-tpm clocksource driver - A new timer driver for the NCPM7xx SoC family" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clocksource/drivers/imx-tpm: Add different counter width support clocksource/drivers/imx-tpm: Correct some registers operation flow clocksource/drivers/imx-tpm: Fix typo of clock name dt-bindings: timer: tpm: fix typo of clock name clocksource/drivers/npcm: Add NPCM7xx timer driver dt-binding: timer: document NPCM7xx timer DT bindings
- Loading branch information
Showing
6 changed files
with
279 additions
and
11 deletions.
There are no files selected for viewing
21 changes: 21 additions & 0 deletions
21
Documentation/devicetree/bindings/timer/nuvoton,npcm7xx-timer.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
Nuvoton NPCM7xx timer | ||
|
||
Nuvoton NPCM7xx have three timer modules, each timer module provides five 24-bit | ||
timer counters. | ||
|
||
Required properties: | ||
- compatible : "nuvoton,npcm750-timer" for Poleg NPCM750. | ||
- reg : Offset and length of the register set for the device. | ||
- interrupts : Contain the timer interrupt with flags for | ||
falling edge. | ||
- clocks : phandle of timer reference clock (usually a 25 MHz clock). | ||
|
||
Example: | ||
|
||
timer@f0008000 { | ||
compatible = "nuvoton,npcm750-timer"; | ||
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; | ||
reg = <0xf0008000 0x50>; | ||
clocks = <&clk NPCM7XX_CLK_TIMER>; | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
// 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); | ||
|