linux/drivers/clocksource/timer-npcm7xx.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2014-2018 Nuvoton Technologies tomer.maimon@nuvoton.com
   4 * All rights reserved.
   5 *
   6 * Copyright 2017 Google, Inc.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/sched.h>
  11#include <linux/init.h>
  12#include <linux/interrupt.h>
  13#include <linux/err.h>
  14#include <linux/clk.h>
  15#include <linux/io.h>
  16#include <linux/clockchips.h>
  17#include <linux/of_irq.h>
  18#include <linux/of_address.h>
  19#include "timer-of.h"
  20
  21/* Timers registers */
  22#define NPCM7XX_REG_TCSR0       0x0 /* Timer 0 Control and Status Register */
  23#define NPCM7XX_REG_TICR0       0x8 /* Timer 0 Initial Count Register */
  24#define NPCM7XX_REG_TCSR1       0x4 /* Timer 1 Control and Status Register */
  25#define NPCM7XX_REG_TICR1       0xc /* Timer 1 Initial Count Register */
  26#define NPCM7XX_REG_TDR1        0x14 /* Timer 1 Data Register */
  27#define NPCM7XX_REG_TISR        0x18 /* Timer Interrupt Status Register */
  28
  29/* Timers control */
  30#define NPCM7XX_Tx_RESETINT             0x1f
  31#define NPCM7XX_Tx_PERIOD               BIT(27)
  32#define NPCM7XX_Tx_INTEN                BIT(29)
  33#define NPCM7XX_Tx_COUNTEN              BIT(30)
  34#define NPCM7XX_Tx_ONESHOT              0x0
  35#define NPCM7XX_Tx_OPER                 GENMASK(28, 27)
  36#define NPCM7XX_Tx_MIN_PRESCALE         0x1
  37#define NPCM7XX_Tx_TDR_MASK_BITS        24
  38#define NPCM7XX_Tx_MAX_CNT              0xFFFFFF
  39#define NPCM7XX_T0_CLR_INT              0x1
  40#define NPCM7XX_Tx_CLR_CSR              0x0
  41
  42/* Timers operating mode */
  43#define NPCM7XX_START_PERIODIC_Tx (NPCM7XX_Tx_PERIOD | NPCM7XX_Tx_COUNTEN | \
  44                                        NPCM7XX_Tx_INTEN | \
  45                                        NPCM7XX_Tx_MIN_PRESCALE)
  46
  47#define NPCM7XX_START_ONESHOT_Tx (NPCM7XX_Tx_ONESHOT | NPCM7XX_Tx_COUNTEN | \
  48                                        NPCM7XX_Tx_INTEN | \
  49                                        NPCM7XX_Tx_MIN_PRESCALE)
  50
  51#define NPCM7XX_START_Tx (NPCM7XX_Tx_COUNTEN | NPCM7XX_Tx_PERIOD | \
  52                                NPCM7XX_Tx_MIN_PRESCALE)
  53
  54#define NPCM7XX_DEFAULT_CSR (NPCM7XX_Tx_CLR_CSR | NPCM7XX_Tx_MIN_PRESCALE)
  55
  56static int npcm7xx_timer_resume(struct clock_event_device *evt)
  57{
  58        struct timer_of *to = to_timer_of(evt);
  59        u32 val;
  60
  61        val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
  62        val |= NPCM7XX_Tx_COUNTEN;
  63        writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
  64
  65        return 0;
  66}
  67
  68static int npcm7xx_timer_shutdown(struct clock_event_device *evt)
  69{
  70        struct timer_of *to = to_timer_of(evt);
  71        u32 val;
  72
  73        val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
  74        val &= ~NPCM7XX_Tx_COUNTEN;
  75        writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
  76
  77        return 0;
  78}
  79
  80static int npcm7xx_timer_oneshot(struct clock_event_device *evt)
  81{
  82        struct timer_of *to = to_timer_of(evt);
  83        u32 val;
  84
  85        val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
  86        val &= ~NPCM7XX_Tx_OPER;
  87        val |= NPCM7XX_START_ONESHOT_Tx;
  88        writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
  89
  90        return 0;
  91}
  92
  93static int npcm7xx_timer_periodic(struct clock_event_device *evt)
  94{
  95        struct timer_of *to = to_timer_of(evt);
  96        u32 val;
  97
  98        writel(timer_of_period(to), timer_of_base(to) + NPCM7XX_REG_TICR0);
  99
 100        val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
 101        val &= ~NPCM7XX_Tx_OPER;
 102        val |= NPCM7XX_START_PERIODIC_Tx;
 103        writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
 104
 105        return 0;
 106}
 107
 108static int npcm7xx_clockevent_set_next_event(unsigned long evt,
 109                struct clock_event_device *clk)
 110{
 111        struct timer_of *to = to_timer_of(clk);
 112        u32 val;
 113
 114        writel(evt, timer_of_base(to) + NPCM7XX_REG_TICR0);
 115        val = readl(timer_of_base(to) + NPCM7XX_REG_TCSR0);
 116        val |= NPCM7XX_START_Tx;
 117        writel(val, timer_of_base(to) + NPCM7XX_REG_TCSR0);
 118
 119        return 0;
 120}
 121
 122static irqreturn_t npcm7xx_timer0_interrupt(int irq, void *dev_id)
 123{
 124        struct clock_event_device *evt = (struct clock_event_device *)dev_id;
 125        struct timer_of *to = to_timer_of(evt);
 126
 127        writel(NPCM7XX_T0_CLR_INT, timer_of_base(to) + NPCM7XX_REG_TISR);
 128
 129        evt->event_handler(evt);
 130
 131        return IRQ_HANDLED;
 132}
 133
 134static struct timer_of npcm7xx_to = {
 135        .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
 136
 137        .clkevt = {
 138                .name               = "npcm7xx-timer0",
 139                .features           = CLOCK_EVT_FEAT_PERIODIC |
 140                                      CLOCK_EVT_FEAT_ONESHOT,
 141                .set_next_event     = npcm7xx_clockevent_set_next_event,
 142                .set_state_shutdown = npcm7xx_timer_shutdown,
 143                .set_state_periodic = npcm7xx_timer_periodic,
 144                .set_state_oneshot  = npcm7xx_timer_oneshot,
 145                .tick_resume        = npcm7xx_timer_resume,
 146                .rating             = 300,
 147        },
 148
 149        .of_irq = {
 150                .handler = npcm7xx_timer0_interrupt,
 151                .flags = IRQF_TIMER | IRQF_IRQPOLL,
 152        },
 153};
 154
 155static void __init npcm7xx_clockevents_init(void)
 156{
 157        writel(NPCM7XX_DEFAULT_CSR,
 158                timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR0);
 159
 160        writel(NPCM7XX_Tx_RESETINT,
 161                timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TISR);
 162
 163        npcm7xx_to.clkevt.cpumask = cpumask_of(0);
 164        clockevents_config_and_register(&npcm7xx_to.clkevt,
 165                                        timer_of_rate(&npcm7xx_to),
 166                                        0x1, NPCM7XX_Tx_MAX_CNT);
 167}
 168
 169static void __init npcm7xx_clocksource_init(void)
 170{
 171        u32 val;
 172
 173        writel(NPCM7XX_DEFAULT_CSR,
 174                timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
 175        writel(NPCM7XX_Tx_MAX_CNT,
 176                timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TICR1);
 177
 178        val = readl(timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
 179        val |= NPCM7XX_START_Tx;
 180        writel(val, timer_of_base(&npcm7xx_to) + NPCM7XX_REG_TCSR1);
 181
 182        clocksource_mmio_init(timer_of_base(&npcm7xx_to) +
 183                                NPCM7XX_REG_TDR1,
 184                                "npcm7xx-timer1", timer_of_rate(&npcm7xx_to),
 185                                200, (unsigned int)NPCM7XX_Tx_TDR_MASK_BITS,
 186                                clocksource_mmio_readl_down);
 187}
 188
 189static int __init npcm7xx_timer_init(struct device_node *np)
 190{
 191        int ret;
 192
 193        ret = timer_of_init(np, &npcm7xx_to);
 194        if (ret)
 195                return ret;
 196
 197        /* Clock input is divided by PRESCALE + 1 before it is fed */
 198        /* to the counter */
 199        npcm7xx_to.of_clk.rate = npcm7xx_to.of_clk.rate /
 200                (NPCM7XX_Tx_MIN_PRESCALE + 1);
 201
 202        npcm7xx_clocksource_init();
 203        npcm7xx_clockevents_init();
 204
 205        pr_info("Enabling NPCM7xx clocksource timer base: %px, IRQ: %d ",
 206                timer_of_base(&npcm7xx_to), timer_of_irq(&npcm7xx_to));
 207
 208        return 0;
 209}
 210
 211TIMER_OF_DECLARE(npcm7xx, "nuvoton,npcm750-timer", npcm7xx_timer_init);
 212
 213