diff options
Diffstat (limited to 'drivers/clocksource')
54 files changed, 1622 insertions, 1284 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0..a7726db13 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX select CLKSRC_MMIO select CLKSRC_OF +config CLKSRC_PISTACHIO + bool + select CLKSRC_OF + config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) @@ -277,7 +281,7 @@ config CLKSRC_MIPS_GIC config CLKSRC_PXA def_bool y if ARCH_PXA || ARCH_SA1100 - select CLKSRC_OF if USE_OF + select CLKSRC_OF if OF help This enables OST0 support available on PXA and SA-11x0 platforms. @@ -293,4 +297,12 @@ config CLKSRC_IMX_GPT depends on ARM && CLKDEV_LOOKUP select CLKSRC_MMIO +config CLKSRC_ST_LPC + bool + depends on ARCH_STI + select CLKSRC_OF if OF + help + Enable this option to use the Low Power controller timer + as clocksource. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f22835496..5c00863c3 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o +obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o @@ -60,3 +61,4 @@ obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o +obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 0aa135ddb..d6e3e4939 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -181,44 +181,36 @@ static irqreturn_t arch_timer_handler_virt_mem(int irq, void *dev_id) return timer_handler(ARCH_TIMER_MEM_VIRT_ACCESS, evt); } -static __always_inline void timer_set_mode(const int access, int mode, - struct clock_event_device *clk) +static __always_inline int timer_shutdown(const int access, + struct clock_event_device *clk) { unsigned long ctrl; - switch (mode) { - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); - ctrl &= ~ARCH_TIMER_CTRL_ENABLE; - arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); - break; - default: - break; - } + + ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, clk); + ctrl &= ~ARCH_TIMER_CTRL_ENABLE; + arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); + + return 0; } -static void arch_timer_set_mode_virt(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_virt(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_VIRT_ACCESS, clk); } -static void arch_timer_set_mode_phys(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_phys(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_PHYS_ACCESS, clk); } -static void arch_timer_set_mode_virt_mem(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_virt_mem(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_MEM_VIRT_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_MEM_VIRT_ACCESS, clk); } -static void arch_timer_set_mode_phys_mem(enum clock_event_mode mode, - struct clock_event_device *clk) +static int arch_timer_shutdown_phys_mem(struct clock_event_device *clk) { - timer_set_mode(ARCH_TIMER_MEM_PHYS_ACCESS, mode, clk); + return timer_shutdown(ARCH_TIMER_MEM_PHYS_ACCESS, clk); } static __always_inline void set_next_event(const int access, unsigned long evt, @@ -273,11 +265,11 @@ static void __arch_timer_setup(unsigned type, clk->cpumask = cpumask_of(smp_processor_id()); if (arch_timer_use_virtual) { clk->irq = arch_timer_ppi[VIRT_PPI]; - clk->set_mode = arch_timer_set_mode_virt; + clk->set_state_shutdown = arch_timer_shutdown_virt; clk->set_next_event = arch_timer_set_next_event_virt; } else { clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; - clk->set_mode = arch_timer_set_mode_phys; + clk->set_state_shutdown = arch_timer_shutdown_phys; clk->set_next_event = arch_timer_set_next_event_phys; } } else { @@ -286,17 +278,17 @@ static void __arch_timer_setup(unsigned type, clk->rating = 400; clk->cpumask = cpu_all_mask; if (arch_timer_mem_use_virtual) { - clk->set_mode = arch_timer_set_mode_virt_mem; + clk->set_state_shutdown = arch_timer_shutdown_virt_mem; clk->set_next_event = arch_timer_set_next_event_virt_mem; } else { - clk->set_mode = arch_timer_set_mode_phys_mem; + clk->set_state_shutdown = arch_timer_shutdown_phys_mem; clk->set_next_event = arch_timer_set_next_event_phys_mem; } } - clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, clk); + clk->set_state_shutdown(clk); clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); } @@ -506,7 +498,7 @@ static void arch_timer_stop(struct clock_event_device *clk) disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); } - clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); + clk->set_state_shutdown(clk); } static int arch_timer_cpu_notify(struct notifier_block *self, diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c index e6833771a..a2cb6fae9 100644 --- a/drivers/clocksource/arm_global_timer.c +++ b/drivers/clocksource/arm_global_timer.c @@ -60,7 +60,7 @@ static struct clock_event_device __percpu *gt_evt; * different to the 32-bit upper value read previously, go back to step 2. * Otherwise the 64-bit timer counter value is correct. */ -static u64 gt_counter_read(void) +static u64 notrace _gt_counter_read(void) { u64 counter; u32 lower; @@ -79,6 +79,11 @@ static u64 gt_counter_read(void) return counter; } +static u64 gt_counter_read(void) +{ + return _gt_counter_read(); +} + /** * To ensure that updates to comparator value register do not set the * Interrupt Status Register proceed as follows: @@ -107,26 +112,21 @@ static void gt_compare_set(unsigned long delta, int periodic) writel(ctrl, gt_base + GT_CONTROL); } -static void gt_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int gt_clockevent_shutdown(struct clock_event_device *evt) { 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; - } + 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); + 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; } static int gt_clockevent_set_next_event(unsigned long evt, @@ -155,7 +155,7 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id) * the Global Timer flag _after_ having incremented * the Comparator register value to a higher value. */ - if (evt->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(evt)) gt_compare_set(ULONG_MAX, 0); writel_relaxed(GT_INT_STATUS_EVENT_FLAG, gt_base + GT_INT_STATUS); @@ -171,7 +171,9 @@ static int gt_clockevents_init(struct clock_event_device *clk) clk->name = "arm_global_timer"; clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERCPU; - clk->set_mode = gt_clockevent_set_mode; + clk->set_state_shutdown = gt_clockevent_shutdown; + clk->set_state_periodic = gt_clockevent_set_periodic; + clk->set_state_oneshot = gt_clockevent_shutdown; clk->set_next_event = gt_clockevent_set_next_event; clk->cpumask = cpumask_of(cpu); clk->rating = 300; @@ -184,7 +186,7 @@ static int gt_clockevents_init(struct clock_event_device *clk) static void gt_clockevents_stop(struct clock_event_device *clk) { - gt_clockevent_set_mode(CLOCK_EVT_MODE_UNUSED, clk); + gt_clockevent_shutdown(clk); disable_percpu_irq(clk->irq); } @@ -204,7 +206,7 @@ static struct clocksource gt_clocksource = { #ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK static u64 notrace gt_sched_clock_read(void) { - return gt_counter_read(); + return _gt_counter_read(); } #endif diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c index 4c2ba5989..217438d39 100644 --- a/drivers/clocksource/asm9260_timer.c +++ b/drivers/clocksource/asm9260_timer.c @@ -120,38 +120,52 @@ static int asm9260_timer_set_next_event(unsigned long delta, return 0; } -static void asm9260_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void __asm9260_timer_shutdown(struct clock_event_device *evt) { /* stop timer0 */ writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG); +} + +static int asm9260_timer_shutdown(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); + return 0; +} + +static int asm9260_timer_set_oneshot(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); + + /* enable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + SET_REG); + return 0; +} + +static int asm9260_timer_set_periodic(struct clock_event_device *evt) +{ + __asm9260_timer_shutdown(evt); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* disable reset and stop on match */ - writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), - priv.base + HW_MCR + CLR_REG); - /* configure match count for TC0 */ - writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); - /* enable TC0 */ - writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* enable reset and stop on match */ - writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), - priv.base + HW_MCR + SET_REG); - break; - default: - break; - } + /* disable reset and stop on match */ + writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0), + priv.base + HW_MCR + CLR_REG); + /* configure match count for TC0 */ + writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0); + /* enable TC0 */ + writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG); + return 0; } static struct clock_event_device event_dev = { - .name = DRIVER_NAME, - .rating = 200, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = asm9260_timer_set_next_event, - .set_mode = asm9260_timer_set_mode, + .name = DRIVER_NAME, + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = asm9260_timer_set_next_event, + .set_state_shutdown = asm9260_timer_shutdown, + .set_state_periodic = asm9260_timer_set_periodic, + .set_state_oneshot = asm9260_timer_set_oneshot, + .tick_resume = asm9260_timer_shutdown, }; static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id) diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index 26ed331b1..6f2822928 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c @@ -54,21 +54,6 @@ static u64 notrace bcm2835_sched_read(void) return readl_relaxed(system_clock); } -static void bcm2835_time_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt_dev) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - default: - WARN(1, "%s: unhandled event mode %d\n", __func__, mode); - break; - } -} - static int bcm2835_time_set_next_event(unsigned long event, struct clock_event_device *evt_dev) { @@ -129,7 +114,6 @@ static void __init bcm2835_timer_init(struct device_node *node) timer->evt.name = node->name; timer->evt.rating = 300; timer->evt.features = CLOCK_EVT_FEAT_ONESHOT; - timer->evt.set_mode = bcm2835_time_set_mode; timer->evt.set_next_event = bcm2835_time_set_next_event; timer->evt.cpumask = cpumask_of(0); timer->act.name = node->name; diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index f1e33d08d..e717e87df 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -127,25 +127,18 @@ static int kona_timer_set_next_event(unsigned long clc, return 0; } -static void kona_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *unused) +static int kona_timer_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* by default mode is one shot don't do any thing */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - kona_timer_disable_and_clear(timers.tmr_regs); - } + kona_timer_disable_and_clear(timers.tmr_regs); + return 0; } static struct clock_event_device kona_clockevent_timer = { .name = "timer 1", .features = CLOCK_EVT_FEAT_ONESHOT, .set_next_event = kona_timer_set_next_event, - .set_mode = kona_timer_set_mode + .set_state_shutdown = kona_timer_shutdown, + .tick_resume = kona_timer_shutdown, }; static void __init kona_timer_clockevents_init(void) diff --git a/drivers/clocksource/cadence_ttc_timer.c b/drivers/clocksource/cadence_ttc_timer.c index 510c8a1d3..9be6018bd 100644 --- a/drivers/clocksource/cadence_ttc_timer.c +++ b/drivers/clocksource/cadence_ttc_timer.c @@ -16,7 +16,6 @@ */ #include <linux/clk.h> -#include <linux/clk-provider.h> #include <linux/interrupt.h> #include <linux/clockchips.h> #include <linux/of_address.h> @@ -191,40 +190,42 @@ static int ttc_set_next_event(unsigned long cycles, } /** - * ttc_set_mode - Sets the mode of timer + * ttc_set_{shutdown|oneshot|periodic} - Sets the state of timer * - * @mode: Mode to be set * @evt: Address of clock event instance **/ -static void ttc_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ttc_shutdown(struct clock_event_device *evt) { struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); struct ttc_timer *timer = &ttce->ttc; u32 ctrl_reg; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ttc_set_interval(timer, DIV_ROUND_CLOSEST(ttce->ttc.freq, - PRESCALE * HZ)); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl_reg = readl_relaxed(timer->base_addr + - TTC_CNT_CNTRL_OFFSET); - ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; - writel_relaxed(ctrl_reg, - timer->base_addr + TTC_CNT_CNTRL_OFFSET); - break; - case CLOCK_EVT_MODE_RESUME: - ctrl_reg = readl_relaxed(timer->base_addr + - TTC_CNT_CNTRL_OFFSET); - ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; - writel_relaxed(ctrl_reg, - timer->base_addr + TTC_CNT_CNTRL_OFFSET); - break; - } + ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); + ctrl_reg |= TTC_CNT_CNTRL_DISABLE_MASK; + writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); + return 0; +} + +static int ttc_set_periodic(struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + + ttc_set_interval(timer, + DIV_ROUND_CLOSEST(ttce->ttc.freq, PRESCALE * HZ)); + return 0; +} + +static int ttc_resume(struct clock_event_device *evt) +{ + struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt); + struct ttc_timer *timer = &ttce->ttc; + u32 ctrl_reg; + + ctrl_reg = readl_relaxed(timer->base_addr + TTC_CNT_CNTRL_OFFSET); + ctrl_reg &= ~TTC_CNT_CNTRL_DISABLE_MASK; + writel_relaxed(ctrl_reg, timer->base_addr + TTC_CNT_CNTRL_OFFSET); + return 0; } static int ttc_rate_change_clocksource_cb(struct notifier_block *nb, @@ -430,7 +431,10 @@ static void __init ttc_setup_clockevent(struct clk *clk, ttcce->ce.name = "ttc_clockevent"; ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ttcce->ce.set_next_event = ttc_set_next_event; - ttcce->ce.set_mode = ttc_set_mode; + ttcce->ce.set_state_shutdown = ttc_shutdown; + ttcce->ce.set_state_periodic = ttc_set_periodic; + ttcce->ce.set_state_oneshot = ttc_shutdown; + ttcce->ce.tick_resume = ttc_resume; ttcce->ce.rating = 200; ttcce->ce.irq = irq; ttcce->ce.cpumask = cpu_possible_mask; diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c new file mode 100644 index 000000000..65ec46744 --- /dev/null +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -0,0 +1,131 @@ +/* + * Clocksource using the Low Power Timer found in the Low Power Controller (LPC) + * + * Copyright (C) 2015 STMicroelectronics – All Rights Reserved + * + * Author(s): Francesco Virlinzi <francesco.virlinzi@st.com> + * Ajit Pal Singh <ajitpal.singh@st.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/init.h> +#include <linux/of_address.h> +#include <linux/sched_clock.h> +#include <linux/slab.h> + +#include <dt-bindings/mfd/st-lpc.h> + +/* Low Power Timer */ +#define LPC_LPT_LSB_OFF 0x400 +#define LPC_LPT_MSB_OFF 0x404 +#define LPC_LPT_START_OFF 0x408 + +static struct st_clksrc_ddata { + struct clk *clk; + void __iomem *base; +} ddata; + +static void __init st_clksrc_reset(void) +{ + writel_relaxed(0, ddata.base + LPC_LPT_START_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF); + writel_relaxed(1, ddata.base + LPC_LPT_START_OFF); +} + +static u64 notrace st_clksrc_sched_clock_read(void) +{ + return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF); +} + +static int __init st_clksrc_init(void) +{ + unsigned long rate; + int ret; + + st_clksrc_reset(); + + rate = clk_get_rate(ddata.clk); + + sched_clock_register(st_clksrc_sched_clock_read, 32, rate); + + ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF, + "clksrc-st-lpc", rate, 300, 32, + clocksource_mmio_readl_up); + if (ret) { + pr_err("clksrc-st-lpc: Failed to register clocksource\n"); + return ret; + } + + return 0; +} + +static int __init st_clksrc_setup_clk(struct device_node *np) +{ + struct clk *clk; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock\n"); + return PTR_ERR(clk); + } + + if (clk_prepare_enable(clk)) { + pr_err("clksrc-st-lpc: Failed to enable LPC clock\n"); + return -EINVAL; + } + + if (!clk_get_rate(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n"); + clk_disable_unprepare(clk); + return -EINVAL; + } + + ddata.clk = clk; + + return 0; +} + +static void __init st_clksrc_of_register(struct device_node *np) +{ + int ret; + uint32_t mode; + + ret = of_property_read_u32(np, "st,lpc-mode", &mode); + if (ret) { + pr_err("clksrc-st-lpc: An LPC mode must be provided\n"); + return; + } + + /* LPC can either run as a Clocksource or in RTC or WDT mode */ + if (mode != ST_LPC_MODE_CLKSRC) + return; + + ddata.base = of_iomap(np, 0); + if (!ddata.base) { + pr_err("clksrc-st-lpc: Unable to map iomem\n"); + return; + } + + if (st_clksrc_setup_clk(np)) { + iounmap(ddata.base); + return; + } + + if (st_clksrc_init()) { + clk_disable_unprepare(ddata.clk); + clk_put(ddata.clk); + iounmap(ddata.base); + return; + } + + pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n", + clk_get_rate(ddata.clk)); +} +CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); diff --git a/drivers/clocksource/clps711x-timer.c b/drivers/clocksource/clps711x-timer.c index d83ec1f2f..cdd86e352 100644 --- a/drivers/clocksource/clps711x-timer.c +++ b/drivers/clocksource/clps711x-timer.c @@ -61,11 +61,6 @@ static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void clps711x_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ -} - static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, unsigned int irq) { @@ -91,7 +86,6 @@ static int __init _clps711x_clkevt_init(struct clk *clock, void __iomem *base, clkevt->name = "clps711x-clockevent"; clkevt->rating = 300; clkevt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_C3STOP; - clkevt->set_mode = clps711x_clockevent_set_mode; clkevt->cpumask = cpumask_of(0); clockevents_config_and_register(clkevt, HZ, 0, 0); diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index db2105290..9a7e37cf5 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c @@ -42,7 +42,6 @@ MODULE_PARM_DESC(irq, "Which IRQ to use for the clock source MFGPT ticks."); * 256 128 .125 512.000 */ -static unsigned int cs5535_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; static struct cs5535_mfgpt_timer *cs5535_event_clock; /* Selected from the table above */ @@ -77,15 +76,17 @@ static void start_timer(struct cs5535_mfgpt_timer *timer, uint16_t delta) MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); } -static void mfgpt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mfgpt_shutdown(struct clock_event_device *evt) { disable_timer(cs5535_event_clock); + return 0; +} - if (mode == CLOCK_EVT_MODE_PERIODIC) - start_timer(cs5535_event_clock, MFGPT_PERIODIC); - - cs5535_tick_mode = mode; +static int mfgpt_set_periodic(struct clock_event_device *evt) +{ + disable_timer(cs5535_event_clock); + start_timer(cs5535_event_clock, MFGPT_PERIODIC); + return 0; } static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) @@ -97,7 +98,10 @@ static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) static struct clock_event_device cs5535_clockevent = { .name = DRV_NAME, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = mfgpt_set_mode, + .set_state_shutdown = mfgpt_shutdown, + .set_state_periodic = mfgpt_set_periodic, + .set_state_oneshot = mfgpt_shutdown, + .tick_resume = mfgpt_shutdown, .set_next_event = mfgpt_next_event, .rating = 250, }; @@ -113,7 +117,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) /* Turn off the clock (and clear the event) */ disable_timer(cs5535_event_clock); - if (cs5535_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) + if (clockevent_state_shutdown(&cs5535_clockevent)) return IRQ_HANDLED; /* Clear the counter */ @@ -121,7 +125,7 @@ static irqreturn_t mfgpt_tick(int irq, void *dev_id) /* Restart the clock in periodic mode */ - if (cs5535_tick_mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(&cs5535_clockevent)) cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c index 31990600f..776b6c86d 100644 --- a/drivers/clocksource/dummy_timer.c +++ b/drivers/clocksource/dummy_timer.c @@ -16,15 +16,6 @@ static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt); -static void dummy_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* - * Core clockevents code will call this when exchanging timer devices. - * We don't need to do anything here. - */ -} - static void dummy_timer_setup(void) { int cpu = smp_processor_id(); @@ -35,7 +26,6 @@ static void dummy_timer_setup(void) CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DUMMY; evt->rating = 100; - evt->set_mode = dummy_timer_set_mode; evt->cpumask = cpumask_of(cpu); clockevents_register_device(evt); diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c index 35a88097a..c76c75006 100644 --- a/drivers/clocksource/dw_apb_timer.c +++ b/drivers/clocksource/dw_apb_timer.c @@ -110,71 +110,87 @@ static void apbt_enable_int(struct dw_apb_timer *timer) apbt_writel(timer, ctrl, APBTMR_N_CONTROL); } -static void apbt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int apbt_shutdown(struct clock_event_device *evt) { + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); unsigned long ctrl; - unsigned long period; + + pr_debug("%s CPU %d state=shutdown\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_set_oneshot(struct clock_event_device *evt) +{ struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + unsigned long ctrl; - pr_debug("%s CPU %d mode=%d\n", __func__, - cpumask_first(evt->cpumask), - mode); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl |= APBTMR_CONTROL_MODE_PERIODIC; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* - * DW APB p. 46, have to disable timer before load counter, - * may cause sync problem. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - udelay(1); - pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); - apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_ONESHOT: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - /* - * set free running mode, this mode will let timer reload max - * timeout which will give time (3min on 25MHz clock) to rearm - * the next event, therefore emulate the one-shot mode. - */ - ctrl &= ~APBTMR_CONTROL_ENABLE; - ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; - - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - /* write again to set free running mode */ - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - - /* - * DW APB p. 46, load counter with all 1s before starting free - * running mode. - */ - apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); - ctrl &= ~APBTMR_CONTROL_INT; - ctrl |= APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); - ctrl &= ~APBTMR_CONTROL_ENABLE; - apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); - break; - - case CLOCK_EVT_MODE_RESUME: - apbt_enable_int(&dw_ced->timer); - break; - } + pr_debug("%s CPU %d state=oneshot\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + /* + * set free running mode, this mode will let timer reload max + * timeout which will give time (3min on 25MHz clock) to rearm + * the next event, therefore emulate the one-shot mode. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; + + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + /* write again to set free running mode */ + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + + /* + * DW APB p. 46, load counter with all 1s before starting free + * running mode. + */ + apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); + ctrl &= ~APBTMR_CONTROL_INT; + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_set_periodic(struct clock_event_device *evt) +{ + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); + unsigned long ctrl; + + pr_debug("%s CPU %d state=periodic\n", __func__, + cpumask_first(evt->cpumask)); + + ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); + ctrl |= APBTMR_CONTROL_MODE_PERIODIC; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + /* + * DW APB p. 46, have to disable timer before load counter, + * may cause sync problem. + */ + ctrl &= ~APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + udelay(1); + pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); + apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); + ctrl |= APBTMR_CONTROL_ENABLE; + apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); + return 0; +} + +static int apbt_resume(struct clock_event_device *evt) +{ + struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); + + pr_debug("%s CPU %d state=resume\n", __func__, + cpumask_first(evt->cpumask)); + + apbt_enable_int(&dw_ced->timer); + return 0; } static int apbt_next_event(unsigned long delta, @@ -232,8 +248,12 @@ dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, &dw_ced->ced); dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); dw_ced->ced.cpumask = cpumask_of(cpu); - dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dw_ced->ced.set_mode = apbt_set_mode; + dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; + dw_ced->ced.set_state_shutdown = apbt_shutdown; + dw_ced->ced.set_state_periodic = apbt_set_periodic; + dw_ced->ced.set_state_oneshot = apbt_set_oneshot; + dw_ced->ced.tick_resume = apbt_resume; dw_ced->ced.set_next_event = apbt_next_event; dw_ced->ced.irq = dw_ced->timer.irq; dw_ced->ced.rating = rating; diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index dc3c6ee04..7a97a34db 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c @@ -251,33 +251,21 @@ static struct em_sti_priv *ced_to_em_sti(struct clock_event_device *ced) return container_of(ced, struct em_sti_priv, ced); } -static void em_sti_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int em_sti_clock_event_shutdown(struct clock_event_device *ced) { struct em_sti_priv *p = ced_to_em_sti(ced); + em_sti_stop(p, USER_CLOCKEVENT); + return 0; +} - /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_ONESHOT: - em_sti_stop(p, USER_CLOCKEVENT); - break; - default: - break; - } +static int em_sti_clock_event_set_oneshot(struct clock_event_device *ced) +{ + struct em_sti_priv *p = ced_to_em_sti(ced); - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&p->pdev->dev, "used for oneshot clock events\n"); - em_sti_start(p, USER_CLOCKEVENT); - clockevents_config(&p->ced, p->rate); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - em_sti_stop(p, USER_CLOCKEVENT); - break; - default: - break; - } + dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + em_sti_start(p, USER_CLOCKEVENT); + clockevents_config(&p->ced, p->rate); + return 0; } static int em_sti_clock_event_next(unsigned long delta, @@ -303,11 +291,12 @@ static void em_sti_register_clockevent(struct em_sti_priv *p) ced->rating = 200; ced->cpumask = cpu_possible_mask; ced->set_next_event = em_sti_clock_event_next; - ced->set_mode = em_sti_clock_event_mode; + ced->set_state_shutdown = em_sti_clock_event_shutdown; + ced->set_state_oneshot = em_sti_clock_event_set_oneshot; dev_info(&p->pdev->dev, "used for clock events\n"); - /* Register with dummy 1 Hz value, gets updated in ->set_mode() */ + /* Register with dummy 1 Hz value, gets updated in ->set_state_oneshot() */ clockevents_config_and_register(ced, 1, 2, 0xffffffff); } diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 9064ff743..029f96ab1 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -257,15 +257,14 @@ static void exynos4_mct_comp0_stop(void) exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB); } -static void exynos4_mct_comp0_start(enum clock_event_mode mode, - unsigned long cycles) +static void exynos4_mct_comp0_start(bool periodic, unsigned long cycles) { unsigned int tcon; cycle_t comp_cycle; tcon = readl_relaxed(reg_base + EXYNOS4_MCT_G_TCON); - if (mode == CLOCK_EVT_MODE_PERIODIC) { + if (periodic) { tcon |= MCT_G_TCON_COMP0_AUTO_INC; exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR); } @@ -283,38 +282,38 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, static int exynos4_comp_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - exynos4_mct_comp0_start(evt->mode, cycles); + exynos4_mct_comp0_start(false, cycles); return 0; } -static void exynos4_comp_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mct_set_state_shutdown(struct clock_event_device *evt) { - unsigned long cycles_per_jiffy; exynos4_mct_comp0_stop(); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - cycles_per_jiffy = - (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); - exynos4_mct_comp0_start(mode, cycles_per_jiffy); - break; +static int mct_set_state_periodic(struct clock_event_device *evt) +{ + unsigned long cycles_per_jiffy; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } + cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) + >> evt->shift); + exynos4_mct_comp0_stop(); + exynos4_mct_comp0_start(true, cycles_per_jiffy); + return 0; } static struct clock_event_device mct_comp_device = { - .name = "mct-comp", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 250, - .set_next_event = exynos4_comp_set_next_event, - .set_mode = exynos4_comp_set_mode, + .name = "mct-comp", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 250, + .set_next_event = exynos4_comp_set_next_event, + .set_state_periodic = mct_set_state_periodic, + .set_state_shutdown = mct_set_state_shutdown, + .set_state_oneshot = mct_set_state_shutdown, + .tick_resume = mct_set_state_shutdown, }; static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id) @@ -390,39 +389,32 @@ static int exynos4_tick_set_next_event(unsigned long cycles, return 0; } -static inline void exynos4_tick_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int set_state_shutdown(struct clock_event_device *evt) +{ + exynos4_mct_tick_stop(this_cpu_ptr(&percpu_mct_tick)); + return 0; +} + +static int set_state_periodic(struct clock_event_device *evt) { struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick); unsigned long cycles_per_jiffy; + cycles_per_jiffy = (((unsigned long long)NSEC_PER_SEC / HZ * evt->mult) + >> evt->shift); exynos4_mct_tick_stop(mevt); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - cycles_per_jiffy = - (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift); - exynos4_mct_tick_start(cycles_per_jiffy, mevt); - break; - - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } + exynos4_mct_tick_start(cycles_per_jiffy, mevt); + return 0; } static void exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) { - struct clock_event_device *evt = &mevt->evt; - /* * This is for supporting oneshot mode. * Mct would generate interrupt periodically * without explicit stopping. */ - if (evt->mode != CLOCK_EVT_MODE_PERIODIC) + if (!clockevent_state_periodic(&mevt->evt)) exynos4_mct_tick_stop(mevt); /* Clear the MCT tick interrupt */ @@ -442,20 +434,21 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int exynos4_local_timer_setup(struct clock_event_device *evt) +static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt) { - struct mct_clock_event_device *mevt; + struct clock_event_device *evt = &mevt->evt; unsigned int cpu = smp_processor_id(); - mevt = container_of(evt, struct mct_clock_event_device, evt); - mevt->base = EXYNOS4_MCT_L_BASE(cpu); snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu); evt->name = mevt->name; evt->cpumask = cpumask_of(cpu); evt->set_next_event = exynos4_tick_set_next_event; - evt->set_mode = exynos4_tick_set_mode; + evt->set_state_periodic = set_state_periodic; + evt->set_state_shutdown = set_state_shutdown; + evt->set_state_oneshot = set_state_shutdown; + evt->tick_resume = set_state_shutdown; evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; evt->rating = 450; @@ -477,9 +470,11 @@ static int exynos4_local_timer_setup(struct clock_event_device *evt) return 0; } -static void exynos4_local_timer_stop(struct clock_event_device *evt) +static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + struct clock_event_device *evt = &mevt->evt; + + evt->set_state_shutdown(evt); if (mct_int_type == MCT_INT_SPI) { if (evt->irq != -1) disable_irq_nosync(evt->irq); @@ -500,11 +495,11 @@ static int exynos4_mct_cpu_notify(struct notifier_block *self, switch (action & ~CPU_TASKS_FROZEN) { case CPU_STARTING: mevt = this_cpu_ptr(&percpu_mct_tick); - exynos4_local_timer_setup(&mevt->evt); + exynos4_local_timer_setup(mevt); break; case CPU_DYING: mevt = this_cpu_ptr(&percpu_mct_tick); - exynos4_local_timer_stop(&mevt->evt); + exynos4_local_timer_stop(mevt); break; } @@ -570,7 +565,7 @@ static void __init exynos4_timer_resources(struct device_node *np, void __iomem goto out_irq; /* Immediately configure the timer on the boot CPU */ - exynos4_local_timer_setup(&mevt->evt); + exynos4_local_timer_setup(mevt); return; out_irq: diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c index 454227d4f..10202f1fd 100644 --- a/drivers/clocksource/fsl_ftm_timer.c +++ b/drivers/clocksource/fsl_ftm_timer.c @@ -118,7 +118,7 @@ static inline void ftm_reset_counter(void __iomem *base) ftm_writel(0x00, base + FTM_CNT); } -static u64 ftm_read_sched_clock(void) +static u64 notrace ftm_read_sched_clock(void) { return ftm_readl(priv->clksrc_base + FTM_CNT); } @@ -153,19 +153,16 @@ static int ftm_set_next_event(unsigned long delta, return 0; } -static void ftm_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ftm_set_oneshot(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ftm_set_next_event(priv->periodic_cyc, evt); - break; - case CLOCK_EVT_MODE_ONESHOT: - ftm_counter_disable(priv->clkevt_base); - break; - default: - return; - } + ftm_counter_disable(priv->clkevt_base); + return 0; +} + +static int ftm_set_periodic(struct clock_event_device *evt) +{ + ftm_set_next_event(priv->periodic_cyc, evt); + return 0; } static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) @@ -174,7 +171,7 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) ftm_irq_acknowledge(priv->clkevt_base); - if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) { + if (likely(clockevent_state_oneshot(evt))) { ftm_irq_disable(priv->clkevt_base); ftm_counter_disable(priv->clkevt_base); } @@ -185,11 +182,13 @@ static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) } static struct clock_event_device ftm_clockevent = { - .name = "Freescale ftm timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = ftm_set_mode, - .set_next_event = ftm_set_next_event, - .rating = 300, + .name = "Freescale ftm timer", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_periodic = ftm_set_periodic, + .set_state_oneshot = ftm_set_oneshot, + .set_next_event = ftm_set_next_event, + .rating = 300, }; static struct irqaction ftm_timer_irq = { diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c index 0214cb3a7..f9b3b7033 100644 --- a/drivers/clocksource/h8300_timer8.c +++ b/drivers/clocksource/h8300_timer8.c @@ -81,7 +81,7 @@ static irqreturn_t timer8_interrupt(int irq, void *dev_id) p->flags |= FLAG_IRQCONTEXT; ctrl_outw(p->tcora, p->mapbase + TCORA); if (!(p->flags & FLAG_SKIPEVENT)) { - if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(&p->ced)) ctrl_outw(0x0000, p->mapbase + _8TCR); p->ced.event_handler(&p->ced); } @@ -169,29 +169,32 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic) timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000); } -static void timer8_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int timer8_clock_event_shutdown(struct clock_event_device *ced) +{ + timer8_stop(ced_to_priv(ced)); + return 0; +} + +static int timer8_clock_event_periodic(struct clock_event_device *ced) { struct timer8_priv *p = ced_to_priv(ced); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&p->pdev->dev, "used for periodic clock events\n"); - timer8_stop(p); - timer8_clock_event_start(p, PERIODIC); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&p->pdev->dev, "used for oneshot clock events\n"); - timer8_stop(p); - timer8_clock_event_start(p, ONESHOT); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - timer8_stop(p); - break; - default: - break; - } + dev_info(&p->pdev->dev, "used for periodic clock events\n"); + timer8_stop(p); + timer8_clock_event_start(p, PERIODIC); + + return 0; +} + +static int timer8_clock_event_oneshot(struct clock_event_device *ced) +{ + struct timer8_priv *p = ced_to_priv(ced); + + dev_info(&p->pdev->dev, "used for oneshot clock events\n"); + timer8_stop(p); + timer8_clock_event_start(p, ONESHOT); + + return 0; } static int timer8_clock_event_next(unsigned long delta, @@ -199,7 +202,7 @@ static int timer8_clock_event_next(unsigned long delta, { struct timer8_priv *p = ced_to_priv(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); timer8_set_next(p, delta - 1); return 0; @@ -246,7 +249,9 @@ static int timer8_setup(struct timer8_priv *p, p->ced.rating = 200; p->ced.cpumask = cpumask_of(0); p->ced.set_next_event = timer8_clock_event_next; - p->ced.set_mode = timer8_clock_event_mode; + p->ced.set_state_shutdown = timer8_clock_event_shutdown; + p->ced.set_state_periodic = timer8_clock_event_periodic; + p->ced.set_state_oneshot = timer8_clock_event_oneshot; ret = setup_irq(irq, &p->irqaction); if (ret < 0) { diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c index 14ee3efcc..0efd36e48 100644 --- a/drivers/clocksource/i8253.c +++ b/drivers/clocksource/i8253.c @@ -100,44 +100,40 @@ int __init clocksource_i8253_init(void) #endif #ifdef CONFIG_CLKEVT_I8253 -/* - * Initialize the PIT timer. - * - * This is also called after resume to bring the PIT into operation again. - */ -static void init_pit_timer(enum clock_event_mode mode, - struct clock_event_device *evt) +static int pit_shutdown(struct clock_event_device *evt) { + if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt)) + return 0; + raw_spin_lock(&i8253_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(0x34, PIT_MODE); - outb_p(PIT_LATCH & 0xff , PIT_CH0); /* LSB */ - outb_p(PIT_LATCH >> 8 , PIT_CH0); /* MSB */ - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - if (evt->mode == CLOCK_EVT_MODE_PERIODIC || - evt->mode == CLOCK_EVT_MODE_ONESHOT) { - outb_p(0x30, PIT_MODE); - outb_p(0, PIT_CH0); - outb_p(0, PIT_CH0); - } - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* One shot setup */ - outb_p(0x38, PIT_MODE); - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + outb_p(0x30, PIT_MODE); + outb_p(0, PIT_CH0); + outb_p(0, PIT_CH0); + + raw_spin_unlock(&i8253_lock); + return 0; +} + +static int pit_set_oneshot(struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + outb_p(0x38, PIT_MODE); + raw_spin_unlock(&i8253_lock); + return 0; +} + +static int pit_set_periodic(struct clock_event_device *evt) +{ + raw_spin_lock(&i8253_lock); + + /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(0x34, PIT_MODE); + outb_p(PIT_LATCH & 0xff, PIT_CH0); /* LSB */ + outb_p(PIT_LATCH >> 8, PIT_CH0); /* MSB */ + raw_spin_unlock(&i8253_lock); + return 0; } /* @@ -160,10 +156,11 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt) * it can be solely used for the global tick. */ struct clock_event_device i8253_clockevent = { - .name = "pit", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = init_pit_timer, - .set_next_event = pit_next_event, + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_state_shutdown = pit_shutdown, + .set_state_periodic = pit_set_periodic, + .set_next_event = pit_next_event, }; /* @@ -172,8 +169,10 @@ struct clock_event_device i8253_clockevent = { */ void __init clockevent_i8253_init(bool oneshot) { - if (oneshot) + if (oneshot) { i8253_clockevent.features |= CLOCK_EVT_FEAT_ONESHOT; + i8253_clockevent.set_state_oneshot = pit_set_oneshot; + } /* * Start pit with the boot cpu mask. x86 might make it global * when it is used as broadcast device later. diff --git a/drivers/clocksource/meson6_timer.c b/drivers/clocksource/meson6_timer.c index 5c15cba41..1fa22c4d2 100644 --- a/drivers/clocksource/meson6_timer.c +++ b/drivers/clocksource/meson6_timer.c @@ -67,25 +67,25 @@ static void meson6_clkevt_time_start(unsigned char timer, bool periodic) writel(val | TIMER_ENABLE_BIT(timer), timer_base + TIMER_ISA_MUX); } -static void meson6_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int meson6_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC/HZ - 1); - meson6_clkevt_time_start(CED_ID, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - meson6_clkevt_time_stop(CED_ID); - meson6_clkevt_time_start(CED_ID, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - meson6_clkevt_time_stop(CED_ID); - break; - } + meson6_clkevt_time_stop(CED_ID); + return 0; +} + +static int meson6_set_oneshot(struct clock_event_device *evt) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_start(CED_ID, false); + return 0; +} + +static int meson6_set_periodic(struct clock_event_device *evt) +{ + meson6_clkevt_time_stop(CED_ID); + meson6_clkevt_time_setup(CED_ID, USEC_PER_SEC / HZ - 1); + meson6_clkevt_time_start(CED_ID, true); + return 0; } static int meson6_clkevt_next_event(unsigned long evt, @@ -99,11 +99,15 @@ static int meson6_clkevt_next_event(unsigned long evt, } static struct clock_event_device meson6_clockevent = { - .name = "meson6_tick", - .rating = 400, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = meson6_clkevt_mode, - .set_next_event = meson6_clkevt_next_event, + .name = "meson6_tick", + .rating = 400, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = meson6_shutdown, + .set_state_periodic = meson6_set_periodic, + .set_state_oneshot = meson6_set_oneshot, + .tick_resume = meson6_shutdown, + .set_next_event = meson6_clkevt_next_event, }; static irqreturn_t meson6_timer_interrupt(int irq, void *dev_id) diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c index b7384b853..bcd5c0d60 100644 --- a/drivers/clocksource/metag_generic.c +++ b/drivers/clocksource/metag_generic.c @@ -56,25 +56,6 @@ static int metag_timer_set_next_event(unsigned long delta, return 0; } -static void metag_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_RESUME: - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - /* We should disable the IRQ here */ - break; - - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_UNUSED: - WARN_ON(1); - break; - }; -} - static cycle_t metag_clocksource_read(struct clocksource *cs) { return __core_reg_get(TXTIMER); @@ -129,7 +110,6 @@ static void arch_timer_setup(unsigned int cpu) clk->rating = 200, clk->shift = 12, clk->irq = tbisig_map(TBID_SIGNUM_TRT), - clk->set_mode = metag_timer_set_mode, clk->set_next_event = metag_timer_set_next_event, clk->mult = div_sc(hwtimer_freq, NSEC_PER_SEC, clk->shift); diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b81ed1a53..02a1945e5 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -33,12 +33,6 @@ static int gic_next_event(unsigned long delta, struct clock_event_device *evt) return res; } -static void gic_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - static irqreturn_t gic_compare_interrupt(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; @@ -67,7 +61,6 @@ static void gic_clockevent_cpu_init(struct clock_event_device *cd) cd->irq = gic_timer_irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = gic_next_event; - cd->set_mode = gic_set_clock_mode; clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff); @@ -79,6 +72,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) disable_percpu_irq(gic_timer_irq); } +static void gic_update_frequency(void *data) +{ + unsigned long rate = (unsigned long)data; + + clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); +} + static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -94,18 +94,40 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } +static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_notifier_data *cnd = data; + + if (action == POST_RATE_CHANGE) + on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); + + return NOTIFY_OK; +} + + static struct notifier_block gic_cpu_nb = { .notifier_call = gic_cpu_notifier, }; +static struct notifier_block gic_clk_nb = { + .notifier_call = gic_clk_notifier, +}; + static int gic_clockevent_init(void) { + int ret; + if (!cpu_has_counter || !gic_frequency) return -ENXIO; - setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + if (ret < 0) + return ret; - register_cpu_notifier(&gic_cpu_nb); + ret = register_cpu_notifier(&gic_cpu_nb); + if (ret < 0) + pr_warn("GIC: Unable to register CPU notifier\n"); gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); @@ -125,18 +147,17 @@ static struct clocksource gic_clocksource = { static void __init __gic_clocksource_init(void) { + int ret; + /* Set clocksource mask. */ gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); /* Calculate a somewhat reasonable rating value. */ gic_clocksource.rating = 200 + gic_frequency / 10000000; - clocksource_register_hz(&gic_clocksource, gic_frequency); - - gic_clockevent_init(); - - /* And finally start the counter */ - gic_start_count(); + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); + if (ret < 0) + pr_warn("GIC: Unable to register clocksource\n"); } void __init gic_clocksource_init(unsigned int frequency) @@ -146,11 +167,16 @@ void __init gic_clocksource_init(unsigned int frequency) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } static void __init gic_clocksource_of_init(struct device_node *node) { struct clk *clk; + int ret; if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) @@ -158,8 +184,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) < 0) { + pr_err("GIC failed to enable clock\n"); + clk_put(clk); + return; + } + gic_frequency = clk_get_rate(clk); - clk_put(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); @@ -172,6 +203,15 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); + + ret = gic_clockevent_init(); + if (!ret && !IS_ERR(clk)) { + if (clk_notifier_register(clk, &gic_clk_nb) < 0) + pr_warn("GIC: Unable to register clock notifier\n"); + } + + /* And finally start the counter */ + gic_start_count(); } CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index 5eb2c3593..19857af65 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -58,25 +58,24 @@ static void __iomem *base; static unsigned int clock_count_per_tick; -static void moxart_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int moxart_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_ONESHOT: - writel(TIMER1_DISABLE, base + TIMER_CR); - writel(~0, base + TIMER1_BASE + REG_LOAD); - break; - case CLOCK_EVT_MODE_PERIODIC: - writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); - writel(TIMER1_ENABLE, base + TIMER_CR); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - writel(TIMER1_DISABLE, base + TIMER_CR); - break; - } + writel(TIMER1_DISABLE, base + TIMER_CR); + return 0; +} + +static int moxart_set_oneshot(struct clock_event_device *evt) +{ + writel(TIMER1_DISABLE, base + TIMER_CR); + writel(~0, base + TIMER1_BASE + REG_LOAD); + return 0; +} + +static int moxart_set_periodic(struct clock_event_device *evt) +{ + writel(clock_count_per_tick, base + TIMER1_BASE + REG_LOAD); + writel(TIMER1_ENABLE, base + TIMER_CR); + return 0; } static int moxart_clkevt_next_event(unsigned long cycles, @@ -95,11 +94,15 @@ static int moxart_clkevt_next_event(unsigned long cycles, } static struct clock_event_device moxart_clockevent = { - .name = "moxart_timer", - .rating = 200, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = moxart_clkevt_mode, - .set_next_event = moxart_clkevt_next_event, + .name = "moxart_timer", + .rating = 200, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = moxart_shutdown, + .set_state_periodic = moxart_set_periodic, + .set_state_oneshot = moxart_set_oneshot, + .tick_resume = moxart_set_oneshot, + .set_next_event = moxart_clkevt_next_event, }; static irqreturn_t moxart_timer_interrupt(int irq, void *dev_id) diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c index 68ab42356..50f0641c6 100644 --- a/drivers/clocksource/mtk_timer.c +++ b/drivers/clocksource/mtk_timer.c @@ -102,27 +102,20 @@ static void mtk_clkevt_time_start(struct mtk_clock_event_device *evt, evt->gpt_base + TIMER_CTRL_REG(timer)); } -static void mtk_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int mtk_clkevt_shutdown(struct clock_event_device *clk) +{ + mtk_clkevt_time_stop(to_mtk_clk(clk), GPT_CLK_EVT); + return 0; +} + +static int mtk_clkevt_set_periodic(struct clock_event_device *clk) { struct mtk_clock_event_device *evt = to_mtk_clk(clk); mtk_clkevt_time_stop(evt, GPT_CLK_EVT); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); - mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - /* No more interrupts will occur as source is disabled */ - break; - } + mtk_clkevt_time_setup(evt, evt->ticks_per_jiffy, GPT_CLK_EVT); + mtk_clkevt_time_start(evt, true, GPT_CLK_EVT); + return 0; } static int mtk_clkevt_next_event(unsigned long event, @@ -196,7 +189,10 @@ static void __init mtk_timer_init(struct device_node *node) evt->dev.name = "mtk_tick"; evt->dev.rating = 300; evt->dev.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - evt->dev.set_mode = mtk_clkevt_mode; + evt->dev.set_state_shutdown = mtk_clkevt_shutdown; + evt->dev.set_state_periodic = mtk_clkevt_set_periodic; + evt->dev.set_state_oneshot = mtk_clkevt_shutdown; + evt->dev.tick_resume = mtk_clkevt_shutdown; evt->dev.set_next_event = mtk_clkevt_next_event; evt->dev.cpumask = cpu_possible_mask; diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c index 445b68a01..f5ce2961c 100644 --- a/drivers/clocksource/mxs_timer.c +++ b/drivers/clocksource/mxs_timer.c @@ -77,7 +77,6 @@ #define BV_TIMROTv2_TIMCTRLn_SELECT__TICK_ALWAYS 0xf static struct clock_event_device mxs_clockevent_device; -static enum clock_event_mode mxs_clockevent_mode = CLOCK_EVT_MODE_UNUSED; static void __iomem *mxs_timrot_base; static u32 timrot_major_version; @@ -141,64 +140,49 @@ static struct irqaction mxs_timer_irq = { .handler = mxs_timer_interrupt, }; -#ifdef DEBUG -static const char *clock_event_mode_label[] const = { - [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", - [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", - [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", - [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED" -}; -#endif /* DEBUG */ - -static void mxs_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static void mxs_irq_clear(char *state) { /* Disable interrupt in timer module */ timrot_irq_disable(); - if (mode != mxs_clockevent_mode) { - /* Set event time into the furthest future */ - if (timrot_is_v1()) - __raw_writel(0xffff, - mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); - else - __raw_writel(0xffffffff, - mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); - - /* Clear pending interrupt */ - timrot_irq_acknowledge(); - } + /* Set event time into the furthest future */ + if (timrot_is_v1()) + __raw_writel(0xffff, mxs_timrot_base + HW_TIMROT_TIMCOUNTn(1)); + else + __raw_writel(0xffffffff, + mxs_timrot_base + HW_TIMROT_FIXED_COUNTn(1)); + + /* Clear pending interrupt */ + timrot_irq_acknowledge(); #ifdef DEBUG - pr_info("%s: changing mode from %s to %s\n", __func__, - clock_event_mode_label[mxs_clockevent_mode], - clock_event_mode_label[mode]); + pr_info("%s: changing mode to %s\n", __func__, state) #endif /* DEBUG */ +} - /* Remember timer mode */ - mxs_clockevent_mode = mode; - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pr_err("%s: Periodic mode is not implemented\n", __func__); - break; - case CLOCK_EVT_MODE_ONESHOT: - timrot_irq_enable(); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appear */ - break; - } +static int mxs_shutdown(struct clock_event_device *evt) +{ + mxs_irq_clear("shutdown"); + + return 0; +} + +static int mxs_set_oneshot(struct clock_event_device *evt) +{ + if (clockevent_state_oneshot(evt)) + mxs_irq_clear("oneshot"); + timrot_irq_enable(); + return 0; } static struct clock_event_device mxs_clockevent_device = { - .name = "mxs_timrot", - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = mxs_set_mode, - .set_next_event = timrotv2_set_next_event, - .rating = 200, + .name = "mxs_timrot", + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = mxs_shutdown, + .set_state_oneshot = mxs_set_oneshot, + .tick_resume = mxs_shutdown, + .set_next_event = timrotv2_set_next_event, + .rating = 200, }; static int __init mxs_clockevent_init(struct clk *timer_clk) diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index a709cfa49..bc8dd443c 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -119,28 +119,27 @@ static void nmdk_clkevt_reset(void) } } -static void nmdk_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int nmdk_clkevt_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - clkevt_periodic = true; - nmdk_clkevt_reset(); - break; - case CLOCK_EVT_MODE_ONESHOT: - clkevt_periodic = false; - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - writel(0, mtu_base + MTU_IMSC); - /* disable timer */ - writel(0, mtu_base + MTU_CR(1)); - /* load some high default value */ - writel(0xffffffff, mtu_base + MTU_LR(1)); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + writel(0, mtu_base + MTU_IMSC); + /* disable timer */ + writel(0, mtu_base + MTU_CR(1)); + /* load some high default value */ + writel(0xffffffff, mtu_base + MTU_LR(1)); + return 0; +} + +static int nmdk_clkevt_set_oneshot(struct clock_event_device *evt) +{ + clkevt_periodic = false; + return 0; +} + +static int nmdk_clkevt_set_periodic(struct clock_event_device *evt) +{ + clkevt_periodic = true; + nmdk_clkevt_reset(); + return 0; } static void nmdk_clksrc_reset(void) @@ -163,13 +162,16 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) } static struct clock_event_device nmdk_clkevt = { - .name = "mtu_1", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_DYNIRQ, - .rating = 200, - .set_mode = nmdk_clkevt_mode, - .set_next_event = nmdk_clkevt_next, - .resume = nmdk_clkevt_resume, + .name = "mtu_1", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_DYNIRQ, + .rating = 200, + .set_state_shutdown = nmdk_clkevt_shutdown, + .set_state_periodic = nmdk_clkevt_set_periodic, + .set_state_oneshot = nmdk_clkevt_set_oneshot, + .set_next_event = nmdk_clkevt_next, + .resume = nmdk_clkevt_resume, }; /* diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index d9438af2b..45b6a4999 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -88,26 +88,12 @@ pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) return (signed)(next - oscr) <= MIN_OSCR_DELTA ? -ETIME : 0; } -static void -pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static int pxa_osmr0_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); - timer_writel(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - /* initializing, released, or preparing for suspend */ - timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); - timer_writel(OSSR_M0, OSSR); - break; - - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - } + /* initializing, released, or preparing for suspend */ + timer_writel(timer_readl(OIER) & ~OIER_E0, OIER); + timer_writel(OSSR_M0, OSSR); + return 0; } #ifdef CONFIG_PM @@ -147,13 +133,14 @@ static void pxa_timer_resume(struct clock_event_device *cedev) #endif static struct clock_event_device ckevt_pxa_osmr0 = { - .name = "osmr0", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = pxa_osmr0_set_next_event, - .set_mode = pxa_osmr0_set_mode, - .suspend = pxa_timer_suspend, - .resume = pxa_timer_resume, + .name = "osmr0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = pxa_osmr0_set_next_event, + .set_state_shutdown = pxa_osmr0_shutdown, + .set_state_oneshot = pxa_osmr0_shutdown, + .suspend = pxa_timer_suspend, + .resume = pxa_timer_resume, }; static struct irqaction pxa_ost0_irq = { diff --git a/drivers/clocksource/qcom-timer.c b/drivers/clocksource/qcom-timer.c index cba2d0155..f8e09f923 100644 --- a/drivers/clocksource/qcom-timer.c +++ b/drivers/clocksource/qcom-timer.c @@ -47,7 +47,7 @@ static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { struct clock_event_device *evt = dev_id; /* Stop the timer tick */ - if (evt->mode == CLOCK_EVT_MODE_ONESHOT) { + if (clockevent_state_oneshot(evt)) { u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~TIMER_ENABLE_EN; writel_relaxed(ctrl, event_base + TIMER_ENABLE); @@ -75,26 +75,14 @@ static int msm_timer_set_next_event(unsigned long cycles, return 0; } -static void msm_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int msm_timer_shutdown(struct clock_event_device *evt) { u32 ctrl; ctrl = readl_relaxed(event_base + TIMER_ENABLE); ctrl &= ~(TIMER_ENABLE_EN | TIMER_ENABLE_CLR_ON_MATCH_EN); - - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Timer is enabled in set_next_event */ - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - break; - } writel_relaxed(ctrl, event_base + TIMER_ENABLE); + return 0; } static struct clock_event_device __percpu *msm_evt; @@ -126,7 +114,9 @@ static int msm_local_timer_setup(struct clock_event_device *evt) evt->name = "msm_timer"; evt->features = CLOCK_EVT_FEAT_ONESHOT; evt->rating = 200; - evt->set_mode = msm_timer_set_mode; + evt->set_state_shutdown = msm_timer_shutdown; + evt->set_state_oneshot = msm_timer_shutdown; + evt->tick_resume = msm_timer_shutdown; evt->set_next_event = msm_timer_set_next_event; evt->cpumask = cpumask_of(cpu); @@ -147,7 +137,7 @@ static int msm_local_timer_setup(struct clock_event_device *evt) static void msm_local_timer_stop(struct clock_event_device *evt) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); } diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c index a35993baf..d3c1742de 100644 --- a/drivers/clocksource/rockchip_timer.c +++ b/drivers/clocksource/rockchip_timer.c @@ -82,23 +82,18 @@ static inline int rk_timer_set_next_event(unsigned long cycles, return 0; } -static inline void rk_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int rk_timer_shutdown(struct clock_event_device *ce) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - rk_timer_disable(ce); - rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce); - rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_RESUME: - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - rk_timer_disable(ce); - break; - } + rk_timer_disable(ce); + return 0; +} + +static int rk_timer_set_periodic(struct clock_event_device *ce) +{ + rk_timer_disable(ce); + rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce); + rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING); + return 0; } static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) @@ -107,7 +102,7 @@ static irqreturn_t rk_timer_interrupt(int irq, void *dev_id) rk_timer_interrupt_clear(ce); - if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(ce)) rk_timer_disable(ce); ce->event_handler(ce); @@ -153,7 +148,7 @@ static void __init rk_timer_init(struct device_node *np) bc_timer.freq = clk_get_rate(timer_clk); irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME); return; } @@ -161,7 +156,8 @@ static void __init rk_timer_init(struct device_node *np) ce->name = TIMER_NAME; ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->set_next_event = rk_timer_set_next_event; - ce->set_mode = rk_timer_set_mode; + ce->set_state_shutdown = rk_timer_shutdown; + ce->set_state_periodic = rk_timer_set_periodic; ce->irq = irq; ce->cpumask = cpumask_of(0); ce->rating = 250; diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c index 5645cfc90..9502bc4c3 100644 --- a/drivers/clocksource/samsung_pwm_timer.c +++ b/drivers/clocksource/samsung_pwm_timer.c @@ -207,25 +207,18 @@ static int samsung_set_next_event(unsigned long cycles, return 0; } -static void samsung_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int samsung_shutdown(struct clock_event_device *evt) { samsung_time_stop(pwm.event_id); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); - samsung_time_start(pwm.event_id, true); - break; - - case CLOCK_EVT_MODE_ONESHOT: - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } +static int samsung_set_periodic(struct clock_event_device *evt) +{ + samsung_time_stop(pwm.event_id); + samsung_time_setup(pwm.event_id, pwm.clock_count_per_tick - 1); + samsung_time_start(pwm.event_id, true); + return 0; } static void samsung_clockevent_resume(struct clock_event_device *cev) @@ -240,12 +233,16 @@ static void samsung_clockevent_resume(struct clock_event_device *cev) } static struct clock_event_device time_event_device = { - .name = "samsung_event_timer", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = samsung_set_next_event, - .set_mode = samsung_set_mode, - .resume = samsung_clockevent_resume, + .name = "samsung_event_timer", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = samsung_set_next_event, + .set_state_shutdown = samsung_shutdown, + .set_state_periodic = samsung_set_periodic, + .set_state_oneshot = samsung_shutdown, + .tick_resume = samsung_shutdown, + .resume = samsung_clockevent_resume, }; static irqreturn_t samsung_clock_event_isr(int irq, void *dev_id) @@ -310,7 +307,7 @@ static void samsung_clocksource_resume(struct clocksource *cs) samsung_time_start(pwm.source_id, true); } -static cycle_t samsung_clocksource_read(struct clocksource *c) +static cycle_t notrace samsung_clocksource_read(struct clocksource *c) { return ~readl_relaxed(pwm.source_reg); } diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index c96de1403..ba73a6eb8 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c @@ -538,7 +538,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) if (ch->flags & FLAG_CLOCKEVENT) { if (!(ch->flags & FLAG_SKIPEVENT)) { - if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) { + if (clockevent_state_oneshot(&ch->ced)) { ch->next_match_value = ch->max_match_value; ch->flags |= FLAG_REPROGRAM; } @@ -554,7 +554,7 @@ static irqreturn_t sh_cmt_interrupt(int irq, void *dev_id) sh_cmt_clock_event_program_verify(ch, 1); if (ch->flags & FLAG_CLOCKEVENT) - if ((ch->ced.mode == CLOCK_EVT_MODE_SHUTDOWN) + if ((clockevent_state_shutdown(&ch->ced)) || (ch->match_value == ch->next_match_value)) ch->flags &= ~FLAG_REPROGRAM; } @@ -726,39 +726,37 @@ static void sh_cmt_clock_event_start(struct sh_cmt_channel *ch, int periodic) sh_cmt_set_next(ch, ch->max_match_value); } -static void sh_cmt_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_cmt_clock_event_shutdown(struct clock_event_device *ced) +{ + struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); + + sh_cmt_stop(ch, FLAG_CLOCKEVENT); + return 0; +} + +static int sh_cmt_clock_event_set_state(struct clock_event_device *ced, + int periodic) { struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_ONESHOT: + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) sh_cmt_stop(ch, FLAG_CLOCKEVENT); - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->cmt->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_cmt_clock_event_start(ch, 1); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&ch->cmt->pdev->dev, - "ch%u: used for oneshot clock events\n", ch->index); - sh_cmt_clock_event_start(ch, 0); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - sh_cmt_stop(ch, FLAG_CLOCKEVENT); - break; - default: - break; - } + dev_info(&ch->cmt->pdev->dev, "ch%u: used for %s clock events\n", + ch->index, periodic ? "periodic" : "oneshot"); + sh_cmt_clock_event_start(ch, periodic); + return 0; +} + +static int sh_cmt_clock_event_set_oneshot(struct clock_event_device *ced) +{ + return sh_cmt_clock_event_set_state(ced, 0); +} + +static int sh_cmt_clock_event_set_periodic(struct clock_event_device *ced) +{ + return sh_cmt_clock_event_set_state(ced, 1); } static int sh_cmt_clock_event_next(unsigned long delta, @@ -766,7 +764,7 @@ static int sh_cmt_clock_event_next(unsigned long delta, { struct sh_cmt_channel *ch = ced_to_sh_cmt(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); if (likely(ch->flags & FLAG_IRQCONTEXT)) ch->next_match_value = delta - 1; else @@ -820,7 +818,9 @@ static int sh_cmt_register_clockevent(struct sh_cmt_channel *ch, ced->rating = 125; ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_cmt_clock_event_next; - ced->set_mode = sh_cmt_clock_event_mode; + ced->set_state_shutdown = sh_cmt_clock_event_shutdown; + ced->set_state_periodic = sh_cmt_clock_event_set_periodic; + ced->set_state_oneshot = sh_cmt_clock_event_set_oneshot; ced->suspend = sh_cmt_clock_event_suspend; ced->resume = sh_cmt_clock_event_resume; @@ -935,9 +935,6 @@ static int sh_cmt_map_memory(struct sh_cmt_device *cmt) static const struct platform_device_id sh_cmt_id_table[] = { { "sh-cmt-16", (kernel_ulong_t)&sh_cmt_info[SH_CMT_16BIT] }, { "sh-cmt-32", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT] }, - { "sh-cmt-32-fast", (kernel_ulong_t)&sh_cmt_info[SH_CMT_32BIT_FAST] }, - { "sh-cmt-48", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT] }, - { "sh-cmt-48-gen2", (kernel_ulong_t)&sh_cmt_info[SH_CMT_48BIT_GEN2] }, { } }; MODULE_DEVICE_TABLE(platform, sh_cmt_id_table); diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index 3d88698cf..53aa7e92a 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c @@ -276,36 +276,27 @@ static struct sh_mtu2_channel *ced_to_sh_mtu2(struct clock_event_device *ced) return container_of(ced, struct sh_mtu2_channel, ced); } -static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_mtu2_clock_event_shutdown(struct clock_event_device *ced) { struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); - int disabled = 0; - /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: + if (clockevent_state_periodic(ced)) sh_mtu2_disable(ch); - disabled = 1; - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->mtu->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_mtu2_enable(ch); - break; - case CLOCK_EVT_MODE_UNUSED: - if (!disabled) - sh_mtu2_disable(ch); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } + return 0; +} + +static int sh_mtu2_clock_event_set_periodic(struct clock_event_device *ced) +{ + struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); + + if (clockevent_state_periodic(ced)) + sh_mtu2_disable(ch); + + dev_info(&ch->mtu->pdev->dev, "ch%u: used for periodic clock events\n", + ch->index); + sh_mtu2_enable(ch); + return 0; } static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) @@ -327,7 +318,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, ced->features = CLOCK_EVT_FEAT_PERIODIC; ced->rating = 200; ced->cpumask = cpu_possible_mask; - ced->set_mode = sh_mtu2_clock_event_mode; + ced->set_state_shutdown = sh_mtu2_clock_event_shutdown; + ced->set_state_periodic = sh_mtu2_clock_event_set_periodic; ced->suspend = sh_mtu2_clock_event_suspend; ced->resume = sh_mtu2_clock_event_resume; diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c index b6b8fa3cd..469e776ec 100644 --- a/drivers/clocksource/sh_tmu.c +++ b/drivers/clocksource/sh_tmu.c @@ -240,7 +240,7 @@ static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id) struct sh_tmu_channel *ch = dev_id; /* disable or acknowledge interrupt */ - if (ch->ced.mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(&ch->ced)) sh_tmu_write(ch, TCR, TCR_TPSC_CLK4); else sh_tmu_write(ch, TCR, TCR_UNIE | TCR_TPSC_CLK4); @@ -358,42 +358,38 @@ static void sh_tmu_clock_event_start(struct sh_tmu_channel *ch, int periodic) } } -static void sh_tmu_clock_event_mode(enum clock_event_mode mode, - struct clock_event_device *ced) +static int sh_tmu_clock_event_shutdown(struct clock_event_device *ced) +{ + struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); + + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) + sh_tmu_disable(ch); + return 0; +} + +static int sh_tmu_clock_event_set_state(struct clock_event_device *ced, + int periodic) { struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); - int disabled = 0; /* deal with old setting first */ - switch (ced->mode) { - case CLOCK_EVT_MODE_PERIODIC: - case CLOCK_EVT_MODE_ONESHOT: + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) sh_tmu_disable(ch); - disabled = 1; - break; - default: - break; - } - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dev_info(&ch->tmu->pdev->dev, - "ch%u: used for periodic clock events\n", ch->index); - sh_tmu_clock_event_start(ch, 1); - break; - case CLOCK_EVT_MODE_ONESHOT: - dev_info(&ch->tmu->pdev->dev, - "ch%u: used for oneshot clock events\n", ch->index); - sh_tmu_clock_event_start(ch, 0); - break; - case CLOCK_EVT_MODE_UNUSED: - if (!disabled) - sh_tmu_disable(ch); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } + dev_info(&ch->tmu->pdev->dev, "ch%u: used for %s clock events\n", + ch->index, periodic ? "periodic" : "oneshot"); + sh_tmu_clock_event_start(ch, periodic); + return 0; +} + +static int sh_tmu_clock_event_set_oneshot(struct clock_event_device *ced) +{ + return sh_tmu_clock_event_set_state(ced, 0); +} + +static int sh_tmu_clock_event_set_periodic(struct clock_event_device *ced) +{ + return sh_tmu_clock_event_set_state(ced, 1); } static int sh_tmu_clock_event_next(unsigned long delta, @@ -401,7 +397,7 @@ static int sh_tmu_clock_event_next(unsigned long delta, { struct sh_tmu_channel *ch = ced_to_sh_tmu(ced); - BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT); + BUG_ON(!clockevent_state_oneshot(ced)); /* program new delta value */ sh_tmu_set_next(ch, delta, 0); @@ -430,7 +426,9 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch, ced->rating = 200; ced->cpumask = cpu_possible_mask; ced->set_next_event = sh_tmu_clock_event_next; - ced->set_mode = sh_tmu_clock_event_mode; + ced->set_state_shutdown = sh_tmu_clock_event_shutdown; + ced->set_state_periodic = sh_tmu_clock_event_set_periodic; + ced->set_state_oneshot = sh_tmu_clock_event_set_oneshot; ced->suspend = sh_tmu_clock_event_suspend; ced->resume = sh_tmu_clock_event_resume; diff --git a/drivers/clocksource/sun4i_timer.c b/drivers/clocksource/sun4i_timer.c index 1928a8912..6f3719d73 100644 --- a/drivers/clocksource/sun4i_timer.c +++ b/drivers/clocksource/sun4i_timer.c @@ -81,25 +81,25 @@ static void sun4i_clkevt_time_start(u8 timer, bool periodic) timer_base + TIMER_CTL_REG(timer)); } -static void sun4i_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clk) +static int sun4i_clkevt_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_setup(0, ticks_per_jiffy); - sun4i_clkevt_time_start(0, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - sun4i_clkevt_time_stop(0); - sun4i_clkevt_time_start(0, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - sun4i_clkevt_time_stop(0); - break; - } + sun4i_clkevt_time_stop(0); + return 0; +} + +static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt) +{ + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_start(0, false); + return 0; +} + +static int sun4i_clkevt_set_periodic(struct clock_event_device *evt) +{ + sun4i_clkevt_time_stop(0); + sun4i_clkevt_time_setup(0, ticks_per_jiffy); + sun4i_clkevt_time_start(0, true); + return 0; } static int sun4i_clkevt_next_event(unsigned long evt, @@ -116,7 +116,10 @@ static struct clock_event_device sun4i_clockevent = { .name = "sun4i_tick", .rating = 350, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sun4i_clkevt_mode, + .set_state_shutdown = sun4i_clkevt_shutdown, + .set_state_periodic = sun4i_clkevt_set_periodic, + .set_state_oneshot = sun4i_clkevt_set_oneshot, + .tick_resume = sun4i_clkevt_shutdown, .set_next_event = sun4i_clkevt_next_event, }; diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 8bdbc45c6..d28d2fe79 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -91,55 +91,62 @@ static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt) */ static u32 timer_clock; -static void tc_mode(enum clock_event_mode m, struct clock_event_device *d) +static int tc_shutdown(struct clock_event_device *d) { struct tc_clkevt_device *tcd = to_tc_clkevt(d); void __iomem *regs = tcd->regs; - if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC - || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) { - __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); - __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); - clk_disable(tcd->clk); - } + __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR)); + __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); + clk_disable(tcd->clk); - switch (m) { + return 0; +} - /* By not making the gentime core emulate periodic mode on top - * of oneshot, we get lower overhead and improved accuracy. - */ - case CLOCK_EVT_MODE_PERIODIC: - clk_enable(tcd->clk); +static int tc_set_oneshot(struct clock_event_device *d) +{ + struct tc_clkevt_device *tcd = to_tc_clkevt(d); + void __iomem *regs = tcd->regs; - /* slow clock, count up to RC, then irq and restart */ - __raw_writel(timer_clock - | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, - regs + ATMEL_TC_REG(2, CMR)); - __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_shutdown(d); - /* Enable clock and interrupts on RC compare */ - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + clk_enable(tcd->clk); - /* go go gadget! */ - __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, - regs + ATMEL_TC_REG(2, CCR)); - break; + /* slow clock, count up to RC, then irq and stop */ + __raw_writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | + ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); - case CLOCK_EVT_MODE_ONESHOT: - clk_enable(tcd->clk); + /* set_next_event() configures and starts the timer */ + return 0; +} - /* slow clock, count up to RC, then irq and stop */ - __raw_writel(timer_clock | ATMEL_TC_CPCSTOP - | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, - regs + ATMEL_TC_REG(2, CMR)); - __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); +static int tc_set_periodic(struct clock_event_device *d) +{ + struct tc_clkevt_device *tcd = to_tc_clkevt(d); + void __iomem *regs = tcd->regs; - /* set_next_event() configures and starts the timer */ - break; + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_shutdown(d); - default: - break; - } + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ + clk_enable(tcd->clk); + + /* slow clock, count up to RC, then irq and restart */ + __raw_writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, + regs + ATMEL_TC_REG(2, CMR)); + __raw_writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); + + /* Enable clock and interrupts on RC compare */ + __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); + + /* go go gadget! */ + __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs + + ATMEL_TC_REG(2, CCR)); + return 0; } static int tc_next_event(unsigned long delta, struct clock_event_device *d) @@ -154,13 +161,15 @@ static int tc_next_event(unsigned long delta, struct clock_event_device *d) static struct tc_clkevt_device clkevt = { .clkevt = { - .name = "tc_clkevt", - .features = CLOCK_EVT_FEAT_PERIODIC - | CLOCK_EVT_FEAT_ONESHOT, + .name = "tc_clkevt", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, /* Should be lower than at91rm9200's system timer */ - .rating = 125, - .set_next_event = tc_next_event, - .set_mode = tc_mode, + .rating = 125, + .set_next_event = tc_next_event, + .set_state_shutdown = tc_shutdown, + .set_state_periodic = tc_set_periodic, + .set_state_oneshot = tc_set_oneshot, }, }; diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c index 5a112d72f..6ebda1177 100644 --- a/drivers/clocksource/tegra20_timer.c +++ b/drivers/clocksource/tegra20_timer.c @@ -72,33 +72,36 @@ static int tegra_timer_set_next_event(unsigned long cycles, return 0; } -static void tegra_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void timer_shutdown(struct clock_event_device *evt) { - u32 reg; - timer_writel(0, TIMER3_BASE + TIMER_PTV); +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - reg = 0xC0000000 | ((1000000/HZ)-1); - timer_writel(reg, TIMER3_BASE + TIMER_PTV); - break; - case CLOCK_EVT_MODE_ONESHOT: - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - break; - } +static int tegra_timer_shutdown(struct clock_event_device *evt) +{ + timer_shutdown(evt); + return 0; +} + +static int tegra_timer_set_periodic(struct clock_event_device *evt) +{ + u32 reg = 0xC0000000 | ((1000000 / HZ) - 1); + + timer_shutdown(evt); + timer_writel(reg, TIMER3_BASE + TIMER_PTV); + return 0; } static struct clock_event_device tegra_clockevent = { - .name = "timer0", - .rating = 300, - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = tegra_timer_set_next_event, - .set_mode = tegra_timer_set_mode, + .name = "timer0", + .rating = 300, + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .set_next_event = tegra_timer_set_next_event, + .set_state_shutdown = tegra_timer_shutdown, + .set_state_periodic = tegra_timer_set_periodic, + .set_state_oneshot = tegra_timer_shutdown, + .tick_resume = tegra_timer_shutdown, }; static u64 notrace tegra_read_sched_clock(void) diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 0c8c5e337..2162796fd 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c @@ -121,33 +121,33 @@ armada_370_xp_clkevt_next_event(unsigned long delta, return 0; } -static void -armada_370_xp_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt) { - if (mode == CLOCK_EVT_MODE_PERIODIC) { + /* + * Disable timer. + */ + local_timer_ctrl_clrset(TIMER0_EN, 0); - /* - * Setup timer to fire at 1/HZ intervals. - */ - writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); - writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); + /* + * ACK pending timer interrupt. + */ + writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); + return 0; +} - /* - * Enable timer. - */ - local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); - } else { - /* - * Disable timer. - */ - local_timer_ctrl_clrset(TIMER0_EN, 0); +static int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt) +{ + /* + * Setup timer to fire at 1/HZ intervals. + */ + writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); + writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); - /* - * ACK pending timer interrupt. - */ - writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); - } + /* + * Enable timer. + */ + local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | enable_mask); + return 0; } static int armada_370_xp_clkevt_irq; @@ -185,7 +185,10 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) evt->shift = 32, evt->rating = 300, evt->set_next_event = armada_370_xp_clkevt_next_event, - evt->set_mode = armada_370_xp_clkevt_mode, + evt->set_state_shutdown = armada_370_xp_clkevt_shutdown; + evt->set_state_periodic = armada_370_xp_clkevt_set_periodic; + evt->set_state_oneshot = armada_370_xp_clkevt_shutdown; + evt->tick_resume = armada_370_xp_clkevt_shutdown; evt->irq = armada_370_xp_clkevt_irq; evt->cpumask = cpumask_of(cpu); @@ -197,7 +200,7 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt) static void armada_370_xp_timer_stop(struct clock_event_device *evt) { - evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); + evt->set_state_shutdown(evt); disable_percpu_irq(evt->irq); } diff --git a/drivers/clocksource/time-efm32.c b/drivers/clocksource/time-efm32.c index 5b6e3d564..b06e4c2be 100644 --- a/drivers/clocksource/time-efm32.c +++ b/drivers/clocksource/time-efm32.c @@ -48,40 +48,42 @@ struct efm32_clock_event_ddata { unsigned periodic_top; }; -static void efm32_clock_event_set_mode(enum clock_event_mode mode, - struct clock_event_device *evtdev) +static int efm32_clock_event_shutdown(struct clock_event_device *evtdev) { struct efm32_clock_event_ddata *ddata = container_of(evtdev, struct efm32_clock_event_ddata, evtdev); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP); - writel_relaxed(TIMERn_CTRL_PRESC_1024 | - TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | - TIMERn_CTRL_MODE_DOWN, - ddata->base + TIMERn_CTRL); - writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); - break; - - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - writel_relaxed(TIMERn_CTRL_PRESC_1024 | - TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | - TIMERn_CTRL_OSMEN | - TIMERn_CTRL_MODE_DOWN, - ddata->base + TIMERn_CTRL); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); - break; - - case CLOCK_EVT_MODE_RESUME: - break; - } + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + return 0; +} + +static int efm32_clock_event_set_oneshot(struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_OSMEN | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + return 0; +} + +static int efm32_clock_event_set_periodic(struct clock_event_device *evtdev) +{ + struct efm32_clock_event_ddata *ddata = + container_of(evtdev, struct efm32_clock_event_ddata, evtdev); + + writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD); + writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP); + writel_relaxed(TIMERn_CTRL_PRESC_1024 | + TIMERn_CTRL_CLKSEL_PRESCHFPERCLK | + TIMERn_CTRL_MODE_DOWN, + ddata->base + TIMERn_CTRL); + writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD); + return 0; } static int efm32_clock_event_set_next_event(unsigned long evt, @@ -112,7 +114,9 @@ static struct efm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name = "efm32 clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_mode = efm32_clock_event_set_mode, + .set_state_shutdown = efm32_clock_event_shutdown, + .set_state_periodic = efm32_clock_event_set_periodic, + .set_state_oneshot = efm32_clock_event_set_oneshot, .set_next_event = efm32_clock_event_set_next_event, .rating = 200, }, diff --git a/drivers/clocksource/time-orion.c b/drivers/clocksource/time-orion.c index 0b3ce0399..0ece7427b 100644 --- a/drivers/clocksource/time-orion.c +++ b/drivers/clocksource/time-orion.c @@ -60,30 +60,36 @@ static int orion_clkevt_next_event(unsigned long delta, return 0; } -static void orion_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int orion_clkevt_shutdown(struct clock_event_device *dev) { - if (mode == CLOCK_EVT_MODE_PERIODIC) { - /* setup and enable periodic timer at 1/HZ intervals */ - writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); - writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); - atomic_io_modify(timer_base + TIMER_CTRL, - TIMER1_RELOAD_EN | TIMER1_EN, - TIMER1_RELOAD_EN | TIMER1_EN); - } else { - /* disable timer */ - atomic_io_modify(timer_base + TIMER_CTRL, - TIMER1_RELOAD_EN | TIMER1_EN, 0); - } + /* disable timer */ + atomic_io_modify(timer_base + TIMER_CTRL, + TIMER1_RELOAD_EN | TIMER1_EN, 0); + return 0; +} + +static int orion_clkevt_set_periodic(struct clock_event_device *dev) +{ + /* setup and enable periodic timer at 1/HZ intervals */ + writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD); + writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL); + atomic_io_modify(timer_base + TIMER_CTRL, + TIMER1_RELOAD_EN | TIMER1_EN, + TIMER1_RELOAD_EN | TIMER1_EN); + return 0; } static struct clock_event_device orion_clkevt = { - .name = "orion_event", - .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 32, - .rating = 300, - .set_next_event = orion_clkevt_next_event, - .set_mode = orion_clkevt_mode, + .name = "orion_event", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .shift = 32, + .rating = 300, + .set_next_event = orion_clkevt_next_event, + .set_state_shutdown = orion_clkevt_shutdown, + .set_state_periodic = orion_clkevt_set_periodic, + .set_state_oneshot = orion_clkevt_shutdown, + .tick_resume = orion_clkevt_shutdown, }; static irqreturn_t orion_clkevt_irq_handler(int irq, void *dev_id) diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c new file mode 100644 index 000000000..bba679900 --- /dev/null +++ b/drivers/clocksource/time-pistachio.c @@ -0,0 +1,218 @@ +/* + * Pistachio clocksource based on general-purpose timers + * + * Copyright (C) 2015 Imagination Technologies + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/sched_clock.h> +#include <linux/time.h> + +/* Top level reg */ +#define CR_TIMER_CTRL_CFG 0x00 +#define TIMER_ME_GLOBAL BIT(0) +#define CR_TIMER_REV 0x10 + +/* Timer specific registers */ +#define TIMER_CFG 0x20 +#define TIMER_ME_LOCAL BIT(0) +#define TIMER_RELOAD_VALUE 0x24 +#define TIMER_CURRENT_VALUE 0x28 +#define TIMER_CURRENT_OVERFLOW_VALUE 0x2C +#define TIMER_IRQ_STATUS 0x30 +#define TIMER_IRQ_CLEAR 0x34 +#define TIMER_IRQ_MASK 0x38 + +#define PERIP_TIMER_CONTROL 0x90 + +/* Timer specific configuration Values */ +#define RELOAD_VALUE 0xffffffff + +struct pistachio_clocksource { + void __iomem *base; + raw_spinlock_t lock; + struct clocksource cs; +}; + +static struct pistachio_clocksource pcs_gpt; + +#define to_pistachio_clocksource(cs) \ + container_of(cs, struct pistachio_clocksource, cs) + +static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id) +{ + return readl(base + 0x20 * gpt_id + offset); +} + +static inline void gpt_writel(void __iomem *base, u32 value, u32 offset, + u32 gpt_id) +{ + writel(value, base + 0x20 * gpt_id + offset); +} + +static cycle_t notrace +pistachio_clocksource_read_cycles(struct clocksource *cs) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 counter, overflw; + unsigned long flags; + + /* + * The counter value is only refreshed after the overflow value is read. + * And they must be read in strict order, hence raw spin lock added. + */ + + raw_spin_lock_irqsave(&pcs->lock, flags); + overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); + counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); + raw_spin_unlock_irqrestore(&pcs->lock, flags); + + return ~(cycle_t)counter; +} + +static u64 notrace pistachio_read_sched_clock(void) +{ + return pistachio_clocksource_read_cycles(&pcs_gpt.cs); +} + +static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx, + int enable) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 val; + + val = gpt_readl(pcs->base, TIMER_CFG, timeridx); + if (enable) + val |= TIMER_ME_LOCAL; + else + val &= ~TIMER_ME_LOCAL; + + gpt_writel(pcs->base, val, TIMER_CFG, timeridx); +} + +static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + + /* Disable GPT local before loading reload value */ + pistachio_clksrc_set_mode(cs, timeridx, false); + gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx); + pistachio_clksrc_set_mode(cs, timeridx, true); +} + +static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx) +{ + /* Disable GPT local */ + pistachio_clksrc_set_mode(cs, timeridx, false); +} + +static int pistachio_clocksource_enable(struct clocksource *cs) +{ + pistachio_clksrc_enable(cs, 0); + return 0; +} + +static void pistachio_clocksource_disable(struct clocksource *cs) +{ + pistachio_clksrc_disable(cs, 0); +} + +/* Desirable clock source for pistachio platform */ +static struct pistachio_clocksource pcs_gpt = { + .cs = { + .name = "gptimer", + .rating = 300, + .enable = pistachio_clocksource_enable, + .disable = pistachio_clocksource_disable, + .read = pistachio_clocksource_read_cycles, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_SUSPEND_NONSTOP, + }, +}; + +static void __init pistachio_clksrc_of_init(struct device_node *node) +{ + struct clk *sys_clk, *fast_clk; + struct regmap *periph_regs; + unsigned long rate; + int ret; + + pcs_gpt.base = of_iomap(node, 0); + if (!pcs_gpt.base) { + pr_err("cannot iomap\n"); + return; + } + + periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); + if (IS_ERR(periph_regs)) { + pr_err("cannot get peripheral regmap (%lu)\n", + PTR_ERR(periph_regs)); + return; + } + + /* Switch to using the fast counter clock */ + ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, + 0xf, 0x0); + if (ret) + return; + + sys_clk = of_clk_get_by_name(node, "sys"); + if (IS_ERR(sys_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(sys_clk)); + return; + } + + fast_clk = of_clk_get_by_name(node, "fast"); + if (IS_ERR(fast_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); + return; + } + + ret = clk_prepare_enable(sys_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + return; + } + + ret = clk_prepare_enable(fast_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + clk_disable_unprepare(sys_clk); + return; + } + + rate = clk_get_rate(fast_clk); + + /* Disable irq's for clocksource usage */ + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 0); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 1); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 2); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 3); + + /* Enable timer block */ + writel(TIMER_ME_GLOBAL, pcs_gpt.base); + + raw_spin_lock_init(&pcs_gpt.lock); + sched_clock_register(pistachio_read_sched_clock, 32, rate); + clocksource_register_hz(&pcs_gpt.cs, rate); +} +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", + pistachio_clksrc_of_init); diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c index 60f9de343..27fa13680 100644 --- a/drivers/clocksource/timer-atlas7.c +++ b/drivers/clocksource/timer-atlas7.c @@ -76,7 +76,7 @@ static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) /* clear timer interrupt */ writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS); - if (ce->mode == CLOCK_EVT_MODE_ONESHOT) + if (clockevent_state_oneshot(ce)) sirfsoc_timer_count_disable(cpu); ce->event_handler(ce); @@ -117,18 +117,11 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, return 0; } -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +/* Oneshot is enabled in set_next_event */ +static int sirfsoc_timer_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - /* enable in set_next_event */ - break; - default: - break; - } - sirfsoc_timer_count_disable(smp_processor_id()); + return 0; } static void sirfsoc_clocksource_suspend(struct clocksource *cs) @@ -193,7 +186,9 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce) ce->name = "local_timer"; ce->features = CLOCK_EVT_FEAT_ONESHOT; ce->rating = 200; - ce->set_mode = sirfsoc_timer_set_mode; + ce->set_state_shutdown = sirfsoc_timer_shutdown; + ce->set_state_oneshot = sirfsoc_timer_shutdown; + ce->tick_resume = sirfsoc_timer_shutdown; ce->set_next_event = sirfsoc_timer_set_next_event; clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60); ce->max_delta_ns = clockevent_delta2ns(-2, ce); diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index c0304ff60..d911c5dca 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -90,33 +90,27 @@ static cycle_t read_pit_clk(struct clocksource *cs) return elapsed; } +static int pit_clkevt_shutdown(struct clock_event_device *dev) +{ + struct pit_data *data = clkevt_to_pit_data(dev); + + /* disable irq, leaving the clocksource active */ + pit_write(data->base, AT91_PIT_MR, (data->cycle - 1) | AT91_PIT_PITEN); + return 0; +} + /* * Clockevent device: interrupts every 1/HZ (== pit_cycles * MCK/16) */ -static void -pit_clkevt_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static int pit_clkevt_set_periodic(struct clock_event_device *dev) { struct pit_data *data = clkevt_to_pit_data(dev); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* update clocksource counter */ - data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); - pit_write(data->base, AT91_PIT_MR, - (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); - break; - case CLOCK_EVT_MODE_ONESHOT: - BUG(); - /* FALLTHROUGH */ - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - /* disable irq, leaving the clocksource active */ - pit_write(data->base, AT91_PIT_MR, - (data->cycle - 1) | AT91_PIT_PITEN); - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + /* update clocksource counter */ + data->cnt += data->cycle * PIT_PICNT(pit_read(data->base, AT91_PIT_PIVR)); + pit_write(data->base, AT91_PIT_MR, + (data->cycle - 1) | AT91_PIT_PITEN | AT91_PIT_PITIEN); + return 0; } static void at91sam926x_pit_suspend(struct clock_event_device *cedev) @@ -162,7 +156,7 @@ static irqreturn_t at91sam926x_pit_interrupt(int irq, void *dev_id) WARN_ON_ONCE(!irqs_disabled()); /* The PIT interrupt may be disabled, and is shared */ - if ((data->clkevt.mode == CLOCK_EVT_MODE_PERIODIC) && + if (clockevent_state_periodic(&data->clkevt) && (pit_read(data->base, AT91_PIT_SR) & AT91_PIT_PITS)) { unsigned nr_ticks; @@ -208,8 +202,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clksrc.mask = CLOCKSOURCE_MASK(bits); data->clksrc.name = "pit"; data->clksrc.rating = 175; - data->clksrc.read = read_pit_clk, - data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS, + data->clksrc.read = read_pit_clk; + data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; clocksource_register_hz(&data->clksrc, pit_rate); /* Set up irq handler */ @@ -227,7 +221,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clkevt.rating = 100; data->clkevt.cpumask = cpumask_of(0); - data->clkevt.set_mode = pit_clkevt_mode; + data->clkevt.set_state_shutdown = pit_clkevt_shutdown; + data->clkevt.set_state_periodic = pit_clkevt_set_periodic; data->clkevt.resume = at91sam926x_pit_resume; data->clkevt.suspend = at91sam926x_pit_suspend; clockevents_register_device(&data->clkevt); diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c index 1692e17e0..41b7b6dc1 100644 --- a/drivers/clocksource/timer-atmel-st.c +++ b/drivers/clocksource/timer-atmel-st.c @@ -106,36 +106,47 @@ static struct clocksource clk32k = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void -clkevt32k_mode(enum clock_event_mode mode, struct clock_event_device *dev) +static void clkdev32k_disable_and_flush_irq(void) { unsigned int val; /* Disable and flush pending timer interrupts */ regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS); regmap_read(regmap_st, AT91_ST_SR, &val); - last_crtr = read_CRTR(); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* PIT for periodic irqs; fixed rate of 1/HZ */ - irqmask = AT91_ST_PITS; - regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* ALM for oneshot irqs, set by next_event() - * before 32 seconds have passed - */ - irqmask = AT91_ST_ALMS; - regmap_write(regmap_st, AT91_ST_RTAR, last_crtr); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - irqmask = 0; - break; - } +} + +static int clkevt32k_shutdown(struct clock_event_device *evt) +{ + clkdev32k_disable_and_flush_irq(); + irqmask = 0; + regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; +} + +static int clkevt32k_set_oneshot(struct clock_event_device *dev) +{ + clkdev32k_disable_and_flush_irq(); + + /* + * ALM for oneshot irqs, set by next_event() + * before 32 seconds have passed. + */ + irqmask = AT91_ST_ALMS; + regmap_write(regmap_st, AT91_ST_RTAR, last_crtr); regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; +} + +static int clkevt32k_set_periodic(struct clock_event_device *dev) +{ + clkdev32k_disable_and_flush_irq(); + + /* PIT for periodic irqs; fixed rate of 1/HZ */ + irqmask = AT91_ST_PITS; + regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH); + regmap_write(regmap_st, AT91_ST_IER, irqmask); + return 0; } static int @@ -170,11 +181,15 @@ clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev) } static struct clock_event_device clkevt = { - .name = "at91_tick", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .rating = 150, - .set_next_event = clkevt32k_next_event, - .set_mode = clkevt32k_mode, + .name = "at91_tick", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 150, + .set_next_event = clkevt32k_next_event, + .set_state_shutdown = clkevt32k_shutdown, + .set_state_periodic = clkevt32k_set_periodic, + .set_state_oneshot = clkevt32k_set_oneshot, + .tick_resume = clkevt32k_shutdown, }; /* diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c index 7f8388cfa..a536eeb63 100644 --- a/drivers/clocksource/timer-digicolor.c +++ b/drivers/clocksource/timer-digicolor.c @@ -87,27 +87,27 @@ static inline void dc_timer_set_count(struct clock_event_device *ce, writel(count, dt->base + COUNT(dt->timer_id)); } -static void digicolor_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int digicolor_clkevt_shutdown(struct clock_event_device *ce) +{ + dc_timer_disable(ce); + return 0; +} + +static int digicolor_clkevt_set_oneshot(struct clock_event_device *ce) +{ + dc_timer_disable(ce); + dc_timer_enable(ce, CONTROL_MODE_ONESHOT); + return 0; +} + +static int digicolor_clkevt_set_periodic(struct clock_event_device *ce) { struct digicolor_timer *dt = dc_timer(ce); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - dc_timer_disable(ce); - dc_timer_set_count(ce, dt->ticks_per_jiffy); - dc_timer_enable(ce, CONTROL_MODE_PERIODIC); - break; - case CLOCK_EVT_MODE_ONESHOT: - dc_timer_disable(ce); - dc_timer_enable(ce, CONTROL_MODE_ONESHOT); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - dc_timer_disable(ce); - break; - } + dc_timer_disable(ce); + dc_timer_set_count(ce, dt->ticks_per_jiffy); + dc_timer_enable(ce, CONTROL_MODE_PERIODIC); + return 0; } static int digicolor_clkevt_next_event(unsigned long evt, @@ -125,7 +125,10 @@ static struct digicolor_timer dc_timer_dev = { .name = "digicolor_tick", .rating = 340, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = digicolor_clkevt_mode, + .set_state_shutdown = digicolor_clkevt_shutdown, + .set_state_periodic = digicolor_clkevt_set_periodic, + .set_state_oneshot = digicolor_clkevt_set_oneshot, + .tick_resume = digicolor_clkevt_shutdown, .set_next_event = digicolor_clkevt_next_event, }, .timer_id = TIMER_C, @@ -140,7 +143,7 @@ static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static u64 digicolor_timer_sched_read(void) +static u64 notrace digicolor_timer_sched_read(void) { return ~readl(dc_timer_dev.base + COUNT(TIMER_B)); } diff --git a/drivers/clocksource/timer-imx-gpt.c b/drivers/clocksource/timer-imx-gpt.c index 86c7eb66b..839aba92f 100644 --- a/drivers/clocksource/timer-imx-gpt.c +++ b/drivers/clocksource/timer-imx-gpt.c @@ -83,7 +83,6 @@ struct imx_timer { struct clk *clk_ipg; const struct imx_gpt_data *gpt; struct clock_event_device ced; - enum clock_event_mode cem; struct irqaction act; }; @@ -212,18 +211,38 @@ static int v2_set_next_event(unsigned long evt, -ETIME : 0; } +static int mxc_shutdown(struct clock_event_device *ced) +{ + struct imx_timer *imxtm = to_imx_timer(ced); + unsigned long flags; + u32 tcn; + + /* + * The timer interrupt generation is disabled at least + * for enough time to call mxc_set_next_event() + */ + local_irq_save(flags); + + /* Disable interrupt in GPT module */ + imxtm->gpt->gpt_irq_disable(imxtm); + + tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); + /* Set event time into far-far future */ + writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); + + /* Clear pending interrupt */ + imxtm->gpt->gpt_irq_acknowledge(imxtm); + #ifdef DEBUG -static const char *clock_event_mode_label[] = { - [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC", - [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT", - [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN", - [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED", - [CLOCK_EVT_MODE_RESUME] = "CLOCK_EVT_MODE_RESUME", -}; + printk(KERN_INFO "%s: changing mode\n", __func__); #endif /* DEBUG */ -static void mxc_set_mode(enum clock_event_mode mode, - struct clock_event_device *ced) + local_irq_restore(flags); + + return 0; +} + +static int mxc_set_oneshot(struct clock_event_device *ced) { struct imx_timer *imxtm = to_imx_timer(ced); unsigned long flags; @@ -237,7 +256,7 @@ static void mxc_set_mode(enum clock_event_mode mode, /* Disable interrupt in GPT module */ imxtm->gpt->gpt_irq_disable(imxtm); - if (mode != imxtm->cem) { + if (!clockevent_state_oneshot(ced)) { u32 tcn = readl_relaxed(imxtm->base + imxtm->gpt->reg_tcn); /* Set event time into far-far future */ writel_relaxed(tcn - 3, imxtm->base + imxtm->gpt->reg_tcmp); @@ -247,37 +266,19 @@ static void mxc_set_mode(enum clock_event_mode mode, } #ifdef DEBUG - printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n", - clock_event_mode_label[imxtm->cem], - clock_event_mode_label[mode]); + printk(KERN_INFO "%s: changing mode\n", __func__); #endif /* DEBUG */ - /* Remember timer mode */ - imxtm->cem = mode; - local_irq_restore(flags); - - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - printk(KERN_ERR"mxc_set_mode: Periodic mode is not " - "supported for i.MX\n"); - break; - case CLOCK_EVT_MODE_ONESHOT: /* * Do not put overhead of interrupt enable/disable into * mxc_set_next_event(), the core has about 4 minutes * to call mxc_set_next_event() or shutdown clock after * mode switching */ - local_irq_save(flags); - imxtm->gpt->gpt_irq_enable(imxtm); - local_irq_restore(flags); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - /* Left event sources disabled, no more interrupts appear */ - break; - } + imxtm->gpt->gpt_irq_enable(imxtm); + local_irq_restore(flags); + + return 0; } /* @@ -303,11 +304,11 @@ static int __init mxc_clockevent_init(struct imx_timer *imxtm) struct clock_event_device *ced = &imxtm->ced; struct irqaction *act = &imxtm->act; - imxtm->cem = CLOCK_EVT_MODE_UNUSED; - ced->name = "mxc_timer1"; ced->features = CLOCK_EVT_FEAT_ONESHOT; - ced->set_mode = mxc_set_mode; + ced->set_state_shutdown = mxc_shutdown; + ced->set_state_oneshot = mxc_set_oneshot; + ced->tick_resume = mxc_shutdown; ced->set_next_event = imxtm->gpt->set_next_event; ced->rating = 200; ced->cpumask = cpumask_of(0); diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c index a68866e0e..3f59ac218 100644 --- a/drivers/clocksource/timer-integrator-ap.c +++ b/drivers/clocksource/timer-integrator-ap.c @@ -75,33 +75,37 @@ static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) +static int clkevt_shutdown(struct clock_event_device *evt) { u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; /* Disable timer */ writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Enable the timer and start the periodic tick */ - writel(timer_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Leave the timer disabled, .set_next_event will enable it */ - ctrl &= ~TIMER_CTRL_PERIODIC; - writel(ctrl, clkevt_base + TIMER_CTRL); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_RESUME: - default: - /* Just leave in disabled state */ - break; - } +static int clkevt_set_oneshot(struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & + ~(TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC); + + /* Leave the timer disabled, .set_next_event will enable it */ + writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; +} +static int clkevt_set_periodic(struct clock_event_device *evt) +{ + u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; + + /* Disable timer */ + writel(ctrl, clkevt_base + TIMER_CTRL); + + /* Enable the timer and start the periodic tick */ + writel(timer_reload, clkevt_base + TIMER_LOAD); + ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; } static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) @@ -116,11 +120,15 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device * } static struct clock_event_device integrator_clockevent = { - .name = "timer1", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = clkevt_set_mode, - .set_next_event = clkevt_set_next_event, - .rating = 300, + .name = "timer1", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = clkevt_shutdown, + .set_state_periodic = clkevt_set_periodic, + .set_state_oneshot = clkevt_set_oneshot, + .tick_resume = clkevt_shutdown, + .set_next_event = clkevt_set_next_event, + .rating = 300, }; static struct irqaction integrator_timer_irq = { diff --git a/drivers/clocksource/timer-keystone.c b/drivers/clocksource/timer-keystone.c index 0250354f7..1cea08cf6 100644 --- a/drivers/clocksource/timer-keystone.c +++ b/drivers/clocksource/timer-keystone.c @@ -72,10 +72,10 @@ static inline void keystone_timer_barrier(void) /** * keystone_timer_config: configures timer to work in oneshot/periodic modes. - * @ mode: mode to configure + * @ mask: mask of the mode to configure * @ period: cycles number to configure for */ -static int keystone_timer_config(u64 period, enum clock_event_mode mode) +static int keystone_timer_config(u64 period, int mask) { u32 tcr; u32 off; @@ -84,16 +84,7 @@ static int keystone_timer_config(u64 period, enum clock_event_mode mode) off = tcr & ~(TCR_ENAMODE_MASK); /* set enable mode */ - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - tcr |= TCR_ENAMODE_ONESHOT_MASK; - break; - case CLOCK_EVT_MODE_PERIODIC: - tcr |= TCR_ENAMODE_PERIODIC_MASK; - break; - default: - return -1; - } + tcr |= mask; /* disable timer */ keystone_timer_writel(off, TCR); @@ -138,24 +129,19 @@ static irqreturn_t keystone_timer_interrupt(int irq, void *dev_id) static int keystone_set_next_event(unsigned long cycles, struct clock_event_device *evt) { - return keystone_timer_config(cycles, evt->mode); + return keystone_timer_config(cycles, TCR_ENAMODE_ONESHOT_MASK); } -static void keystone_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int keystone_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - keystone_timer_config(timer.hz_period, CLOCK_EVT_MODE_PERIODIC); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_ONESHOT: - keystone_timer_disable(); - break; - default: - break; - } + keystone_timer_disable(); + return 0; +} + +static int keystone_set_periodic(struct clock_event_device *evt) +{ + keystone_timer_config(timer.hz_period, TCR_ENAMODE_PERIODIC_MASK); + return 0; } static void __init keystone_timer_init(struct device_node *np) @@ -166,7 +152,7 @@ static void __init keystone_timer_init(struct device_node *np) int irq, error; irq = irq_of_parse_and_map(np, 0); - if (irq == NO_IRQ) { + if (!irq) { pr_err("%s: failed to map interrupts\n", __func__); return; } @@ -222,7 +208,9 @@ static void __init keystone_timer_init(struct device_node *np) /* setup clockevent */ event_dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; event_dev->set_next_event = keystone_set_next_event; - event_dev->set_mode = keystone_set_mode; + event_dev->set_state_shutdown = keystone_shutdown; + event_dev->set_state_periodic = keystone_set_periodic; + event_dev->set_state_oneshot = keystone_shutdown; event_dev->cpumask = cpu_all_mask; event_dev->owner = THIS_MODULE; event_dev->name = TIMER_NAME; diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c index ce18d570e..2854c663e 100644 --- a/drivers/clocksource/timer-prima2.c +++ b/drivers/clocksource/timer-prima2.c @@ -73,7 +73,7 @@ static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id) } /* read 64-bit timer counter */ -static cycle_t sirfsoc_timer_read(struct clocksource *cs) +static cycle_t notrace sirfsoc_timer_read(struct clocksource *cs) { u64 cycles; @@ -104,26 +104,21 @@ static int sirfsoc_timer_set_next_event(unsigned long delta, return next - now > delta ? -ETIME : 0; } -static void sirfsoc_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *ce) +static int sirfsoc_timer_shutdown(struct clock_event_device *evt) { u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - WARN_ON(1); - break; - case CLOCK_EVT_MODE_ONESHOT: - writel_relaxed(val | BIT(0), - sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - writel_relaxed(val & ~BIT(0), - sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - break; - } + + writel_relaxed(val & ~BIT(0), + sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + return 0; +} + +static int sirfsoc_timer_set_oneshot(struct clock_event_device *evt) +{ + u32 val = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + + writel_relaxed(val | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_INT_EN); + return 0; } static void sirfsoc_clocksource_suspend(struct clocksource *cs) @@ -157,7 +152,8 @@ static struct clock_event_device sirfsoc_clockevent = { .name = "sirfsoc_clockevent", .rating = 200, .features = CLOCK_EVT_FEAT_ONESHOT, - .set_mode = sirfsoc_timer_set_mode, + .set_state_shutdown = sirfsoc_timer_shutdown, + .set_state_oneshot = sirfsoc_timer_set_oneshot, .set_next_event = sirfsoc_timer_set_next_event, }; diff --git a/drivers/clocksource/timer-sp804.c b/drivers/clocksource/timer-sp804.c index ca02503f1..5f45b9ade 100644 --- a/drivers/clocksource/timer-sp804.c +++ b/drivers/clocksource/timer-sp804.c @@ -133,50 +133,50 @@ static irqreturn_t sp804_timer_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void sp804_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static inline void timer_shutdown(struct clock_event_device *evt) { - unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE; + writel(0, clkevt_base + TIMER_CTRL); +} - writel(ctrl, clkevt_base + TIMER_CTRL); +static int sp804_shutdown(struct clock_event_device *evt) +{ + timer_shutdown(evt); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel(clkevt_reload, clkevt_base + TIMER_LOAD); - ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* period set, and timer enabled in 'next_event' hook */ - ctrl |= TIMER_CTRL_ONESHOT; - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - break; - } +static int sp804_set_periodic(struct clock_event_device *evt) +{ + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | + TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; + timer_shutdown(evt); + writel(clkevt_reload, clkevt_base + TIMER_LOAD); writel(ctrl, clkevt_base + TIMER_CTRL); + return 0; } static int sp804_set_next_event(unsigned long next, struct clock_event_device *evt) { - unsigned long ctrl = readl(clkevt_base + TIMER_CTRL); + unsigned long ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_IE | + TIMER_CTRL_ONESHOT | TIMER_CTRL_ENABLE; writel(next, clkevt_base + TIMER_LOAD); - writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL); + writel(ctrl, clkevt_base + TIMER_CTRL); return 0; } static struct clock_event_device sp804_clockevent = { - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_DYNIRQ, - .set_mode = sp804_set_mode, - .set_next_event = sp804_set_next_event, - .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_DYNIRQ, + .set_state_shutdown = sp804_shutdown, + .set_state_periodic = sp804_set_periodic, + .set_state_oneshot = sp804_shutdown, + .tick_resume = sp804_shutdown, + .set_next_event = sp804_set_next_event, + .rating = 300, }; static struct irqaction sp804_timer_irq = { diff --git a/drivers/clocksource/timer-stm32.c b/drivers/clocksource/timer-stm32.c index a97e8b507..f3dcb7679 100644 --- a/drivers/clocksource/timer-stm32.c +++ b/drivers/clocksource/timer-stm32.c @@ -40,24 +40,25 @@ struct stm32_clock_event_ddata { void __iomem *base; }; -static void stm32_clock_event_set_mode(enum clock_event_mode mode, - struct clock_event_device *evtdev) +static int stm32_clock_event_shutdown(struct clock_event_device *evtdev) { struct stm32_clock_event_ddata *data = container_of(evtdev, struct stm32_clock_event_ddata, evtdev); void *base = data->base; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - writel_relaxed(data->periodic_top, base + TIM_ARR); - writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); - break; + writel_relaxed(0, base + TIM_CR1); + return 0; +} - case CLOCK_EVT_MODE_ONESHOT: - default: - writel_relaxed(0, base + TIM_CR1); - break; - } +static int stm32_clock_event_set_periodic(struct clock_event_device *evtdev) +{ + struct stm32_clock_event_ddata *data = + container_of(evtdev, struct stm32_clock_event_ddata, evtdev); + void *base = data->base; + + writel_relaxed(data->periodic_top, base + TIM_ARR); + writel_relaxed(TIM_CR1_ARPE | TIM_CR1_CEN, base + TIM_CR1); + return 0; } static int stm32_clock_event_set_next_event(unsigned long evt, @@ -88,7 +89,10 @@ static struct stm32_clock_event_ddata clock_event_ddata = { .evtdev = { .name = "stm32 clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .set_mode = stm32_clock_event_set_mode, + .set_state_shutdown = stm32_clock_event_shutdown, + .set_state_periodic = stm32_clock_event_set_periodic, + .set_state_oneshot = stm32_clock_event_shutdown, + .tick_resume = stm32_clock_event_shutdown, .set_next_event = stm32_clock_event_set_next_event, .rating = 200, }, diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c index 0ffb4ea7c..bca9573e0 100644 --- a/drivers/clocksource/timer-sun5i.c +++ b/drivers/clocksource/timer-sun5i.c @@ -103,27 +103,31 @@ static void sun5i_clkevt_time_start(struct sun5i_timer_clkevt *ce, u8 timer, boo ce->timer.base + TIMER_CTL_REG(timer)); } -static void sun5i_clkevt_mode(enum clock_event_mode mode, - struct clock_event_device *clkevt) +static int sun5i_clkevt_shutdown(struct clock_event_device *clkevt) { struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - sun5i_clkevt_time_stop(ce, 0); - sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy); - sun5i_clkevt_time_start(ce, 0, true); - break; - case CLOCK_EVT_MODE_ONESHOT: - sun5i_clkevt_time_stop(ce, 0); - sun5i_clkevt_time_start(ce, 0, false); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - default: - sun5i_clkevt_time_stop(ce, 0); - break; - } + sun5i_clkevt_time_stop(ce, 0); + return 0; +} + +static int sun5i_clkevt_set_oneshot(struct clock_event_device *clkevt) +{ + struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); + + sun5i_clkevt_time_stop(ce, 0); + sun5i_clkevt_time_start(ce, 0, false); + return 0; +} + +static int sun5i_clkevt_set_periodic(struct clock_event_device *clkevt) +{ + struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt); + + sun5i_clkevt_time_stop(ce, 0); + sun5i_clkevt_time_setup(ce, 0, ce->timer.ticks_per_jiffy); + sun5i_clkevt_time_start(ce, 0, true); + return 0; } static int sun5i_clkevt_next_event(unsigned long evt, @@ -286,7 +290,10 @@ static int __init sun5i_setup_clockevent(struct device_node *node, void __iomem ce->clkevt.name = node->name; ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; ce->clkevt.set_next_event = sun5i_clkevt_next_event; - ce->clkevt.set_mode = sun5i_clkevt_mode; + ce->clkevt.set_state_shutdown = sun5i_clkevt_shutdown; + ce->clkevt.set_state_periodic = sun5i_clkevt_set_periodic; + ce->clkevt.set_state_oneshot = sun5i_clkevt_set_oneshot; + ce->clkevt.tick_resume = sun5i_clkevt_shutdown; ce->clkevt.rating = 340; ce->clkevt.irq = irq; ce->clkevt.cpumask = cpu_possible_mask; diff --git a/drivers/clocksource/timer-u300.c b/drivers/clocksource/timer-u300.c index 5dcf75697..1744b2438 100644 --- a/drivers/clocksource/timer-u300.c +++ b/drivers/clocksource/timer-u300.c @@ -187,85 +187,82 @@ struct u300_clockevent_data { unsigned ticks_per_jiffy; }; +static int u300_shutdown(struct clock_event_device *evt) +{ + /* Disable interrupts on GP1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + return 0; +} + /* - * The u300_set_mode() function is always called first, if we - * have oneshot timer active, the oneshot scheduling function + * If we have oneshot timer active, the oneshot scheduling function * u300_set_next_event() is called immediately after. */ -static void u300_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int u300_set_oneshot(struct clock_event_device *evt) +{ + /* Just return; here? */ + /* + * The actual event will be programmed by the next event hook, + * so we just set a dummy value somewhere at the end of the + * universe here. + */ + /* Disable interrupts on GPT1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 while we're reprogramming it. */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + /* + * Expire far in the future, u300_set_next_event() will be + * called soon... + */ + writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC); + /* We run one shot per tick here! */ + writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, + u300_timer_base + U300_TIMER_APP_SGPT1M); + /* Enable interrupts for this timer */ + writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Enable timer */ + writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, + u300_timer_base + U300_TIMER_APP_EGPT1); + return 0; +} + +static int u300_set_periodic(struct clock_event_device *evt) { struct u300_clockevent_data *cevdata = container_of(evt, struct u300_clockevent_data, cevd); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - /* Disable interrupts on GPT1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 while we're reprogramming it. */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - /* - * Set the periodic mode to a certain number of ticks per - * jiffy. - */ - writel(cevdata->ticks_per_jiffy, - u300_timer_base + U300_TIMER_APP_GPT1TC); - /* - * Set continuous mode, so the timer keeps triggering - * interrupts. - */ - writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, - u300_timer_base + U300_TIMER_APP_SGPT1M); - /* Enable timer interrupts */ - writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Then enable the OS timer again */ - writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - u300_timer_base + U300_TIMER_APP_EGPT1); - break; - case CLOCK_EVT_MODE_ONESHOT: - /* Just break; here? */ - /* - * The actual event will be programmed by the next event hook, - * so we just set a dummy value somewhere at the end of the - * universe here. - */ - /* Disable interrupts on GPT1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 while we're reprogramming it. */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - /* - * Expire far in the future, u300_set_next_event() will be - * called soon... - */ - writel(0xFFFFFFFF, u300_timer_base + U300_TIMER_APP_GPT1TC); - /* We run one shot per tick here! */ - writel(U300_TIMER_APP_SGPT1M_MODE_ONE_SHOT, - u300_timer_base + U300_TIMER_APP_SGPT1M); - /* Enable interrupts for this timer */ - writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Enable timer */ - writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, - u300_timer_base + U300_TIMER_APP_EGPT1); - break; - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - /* Disable interrupts on GP1 */ - writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, - u300_timer_base + U300_TIMER_APP_GPT1IE); - /* Disable GP1 */ - writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, - u300_timer_base + U300_TIMER_APP_DGPT1); - break; - case CLOCK_EVT_MODE_RESUME: - /* Ignore this call */ - break; - } + /* Disable interrupts on GPT1 */ + writel(U300_TIMER_APP_GPT1IE_IRQ_DISABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Disable GP1 while we're reprogramming it. */ + writel(U300_TIMER_APP_DGPT1_TIMER_DISABLE, + u300_timer_base + U300_TIMER_APP_DGPT1); + /* + * Set the periodic mode to a certain number of ticks per + * jiffy. + */ + writel(cevdata->ticks_per_jiffy, + u300_timer_base + U300_TIMER_APP_GPT1TC); + /* + * Set continuous mode, so the timer keeps triggering + * interrupts. + */ + writel(U300_TIMER_APP_SGPT1M_MODE_CONTINUOUS, + u300_timer_base + U300_TIMER_APP_SGPT1M); + /* Enable timer interrupts */ + writel(U300_TIMER_APP_GPT1IE_IRQ_ENABLE, + u300_timer_base + U300_TIMER_APP_GPT1IE); + /* Then enable the OS timer again */ + writel(U300_TIMER_APP_EGPT1_TIMER_ENABLE, + u300_timer_base + U300_TIMER_APP_EGPT1); + return 0; } /* @@ -309,13 +306,15 @@ static int u300_set_next_event(unsigned long cycles, static struct u300_clockevent_data u300_clockevent_data = { /* Use general purpose timer 1 as clock event */ .cevd = { - .name = "GPT1", + .name = "GPT1", /* Reasonably fast and accurate clock event */ - .rating = 300, - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = u300_set_next_event, - .set_mode = u300_set_mode, + .rating = 300, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = u300_set_next_event, + .set_state_shutdown = u300_shutdown, + .set_state_periodic = u300_set_periodic, + .set_state_oneshot = u300_set_oneshot, }, }; diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c index b45ac6229..a0e6c6853 100644 --- a/drivers/clocksource/vf_pit_timer.c +++ b/drivers/clocksource/vf_pit_timer.c @@ -52,7 +52,7 @@ static inline void pit_irq_acknowledge(void) __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG); } -static u64 pit_read_sched_clock(void) +static u64 notrace pit_read_sched_clock(void) { return ~__raw_readl(clksrc_base + PITCVAL); } @@ -86,20 +86,16 @@ static int pit_set_next_event(unsigned long delta, return 0; } -static void pit_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int pit_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pit_set_next_event(cycle_per_jiffy, evt); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - pit_timer_disable(); - break; - default: - break; - } + pit_timer_disable(); + return 0; +} + +static int pit_set_periodic(struct clock_event_device *evt) +{ + pit_set_next_event(cycle_per_jiffy, evt); + return 0; } static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) @@ -114,7 +110,7 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) * and start the counter again. So software need to disable the timer * to stop the counter loop in ONESHOT mode. */ - if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT)) + if (likely(clockevent_state_oneshot(evt))) pit_timer_disable(); evt->event_handler(evt); @@ -125,7 +121,8 @@ static irqreturn_t pit_timer_interrupt(int irq, void *dev_id) static struct clock_event_device clockevent_pit = { .name = "VF pit timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = pit_set_mode, + .set_state_shutdown = pit_shutdown, + .set_state_periodic = pit_set_periodic, .set_next_event = pit_set_next_event, .rating = 300, }; diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c index 1098ed3b9..a92e94b40 100644 --- a/drivers/clocksource/vt8500_timer.c +++ b/drivers/clocksource/vt8500_timer.c @@ -88,29 +88,20 @@ static int vt8500_timer_set_next_event(unsigned long cycles, return 0; } -static void vt8500_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int vt8500_shutdown(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_PERIODIC: - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - writel(readl(regbase + TIMER_CTRL_VAL) | 1, - regbase + TIMER_CTRL_VAL); - writel(0, regbase + TIMER_IER_VAL); - break; - } + writel(readl(regbase + TIMER_CTRL_VAL) | 1, regbase + TIMER_CTRL_VAL); + writel(0, regbase + TIMER_IER_VAL); + return 0; } static struct clock_event_device clockevent = { - .name = "vt8500_timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_next_event = vt8500_timer_set_next_event, - .set_mode = vt8500_timer_set_mode, + .name = "vt8500_timer", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_next_event = vt8500_timer_set_next_event, + .set_state_shutdown = vt8500_shutdown, + .set_state_oneshot = vt8500_shutdown, }; static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c index 7ce442148..ceaa6133f 100644 --- a/drivers/clocksource/zevio-timer.c +++ b/drivers/clocksource/zevio-timer.c @@ -76,32 +76,28 @@ static int zevio_timer_set_event(unsigned long delta, return 0; } -static void zevio_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *dev) +static int zevio_timer_shutdown(struct clock_event_device *dev) { struct zevio_timer *timer = container_of(dev, struct zevio_timer, clkevt); - switch (mode) { - case CLOCK_EVT_MODE_RESUME: - case CLOCK_EVT_MODE_ONESHOT: - /* Enable timer interrupts */ - writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK); - writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - /* Disable timer interrupts */ - writel(0, timer->interrupt_regs + IO_INTR_MSK); - writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); - /* Stop timer */ - writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL); - break; - case CLOCK_EVT_MODE_PERIODIC: - default: - /* Unsupported */ - break; - } + /* Disable timer interrupts */ + writel(0, timer->interrupt_regs + IO_INTR_MSK); + writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); + /* Stop timer */ + writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL); + return 0; +} + +static int zevio_timer_set_oneshot(struct clock_event_device *dev) +{ + struct zevio_timer *timer = container_of(dev, struct zevio_timer, + clkevt); + + /* Enable timer interrupts */ + writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK); + writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK); + return 0; } static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id) @@ -162,7 +158,9 @@ static int __init zevio_timer_add(struct device_node *node) if (timer->interrupt_regs && irqnr) { timer->clkevt.name = timer->clockevent_name; timer->clkevt.set_next_event = zevio_timer_set_event; - timer->clkevt.set_mode = zevio_timer_set_mode; + timer->clkevt.set_state_shutdown = zevio_timer_shutdown; + timer->clkevt.set_state_oneshot = zevio_timer_set_oneshot; + timer->clkevt.tick_resume = zevio_timer_set_oneshot; timer->clkevt.rating = 200; timer->clkevt.cpumask = cpu_all_mask; timer->clkevt.features = CLOCK_EVT_FEAT_ONESHOT; |