Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * linux/arch/arm/mach-at91/at91rm9200_time.c
0004  *
0005  *  Copyright (C) 2003 SAN People
0006  *  Copyright (C) 2003 ATMEL
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/irq.h>
0012 #include <linux/clk.h>
0013 #include <linux/clockchips.h>
0014 #include <linux/export.h>
0015 #include <linux/mfd/syscon.h>
0016 #include <linux/mfd/syscon/atmel-st.h>
0017 #include <linux/of_irq.h>
0018 #include <linux/regmap.h>
0019 
0020 static unsigned long last_crtr;
0021 static u32 irqmask;
0022 static struct clock_event_device clkevt;
0023 static struct regmap *regmap_st;
0024 static int timer_latch;
0025 
0026 /*
0027  * The ST_CRTR is updated asynchronously to the master clock ... but
0028  * the updates as seen by the CPU don't seem to be strictly monotonic.
0029  * Waiting until we read the same value twice avoids glitching.
0030  */
0031 static inline unsigned long read_CRTR(void)
0032 {
0033     unsigned int x1, x2;
0034 
0035     regmap_read(regmap_st, AT91_ST_CRTR, &x1);
0036     do {
0037         regmap_read(regmap_st, AT91_ST_CRTR, &x2);
0038         if (x1 == x2)
0039             break;
0040         x1 = x2;
0041     } while (1);
0042     return x1;
0043 }
0044 
0045 /*
0046  * IRQ handler for the timer.
0047  */
0048 static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
0049 {
0050     u32 sr;
0051 
0052     regmap_read(regmap_st, AT91_ST_SR, &sr);
0053     sr &= irqmask;
0054 
0055     /*
0056      * irqs should be disabled here, but as the irq is shared they are only
0057      * guaranteed to be off if the timer irq is registered first.
0058      */
0059     WARN_ON_ONCE(!irqs_disabled());
0060 
0061     /* simulate "oneshot" timer with alarm */
0062     if (sr & AT91_ST_ALMS) {
0063         clkevt.event_handler(&clkevt);
0064         return IRQ_HANDLED;
0065     }
0066 
0067     /* periodic mode should handle delayed ticks */
0068     if (sr & AT91_ST_PITS) {
0069         u32 crtr = read_CRTR();
0070 
0071         while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) {
0072             last_crtr += timer_latch;
0073             clkevt.event_handler(&clkevt);
0074         }
0075         return IRQ_HANDLED;
0076     }
0077 
0078     /* this irq is shared ... */
0079     return IRQ_NONE;
0080 }
0081 
0082 static u64 read_clk32k(struct clocksource *cs)
0083 {
0084     return read_CRTR();
0085 }
0086 
0087 static struct clocksource clk32k = {
0088     .name       = "32k_counter",
0089     .rating     = 150,
0090     .read       = read_clk32k,
0091     .mask       = CLOCKSOURCE_MASK(20),
0092     .flags      = CLOCK_SOURCE_IS_CONTINUOUS,
0093 };
0094 
0095 static void clkdev32k_disable_and_flush_irq(void)
0096 {
0097     unsigned int val;
0098 
0099     /* Disable and flush pending timer interrupts */
0100     regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
0101     regmap_read(regmap_st, AT91_ST_SR, &val);
0102     last_crtr = read_CRTR();
0103 }
0104 
0105 static int clkevt32k_shutdown(struct clock_event_device *evt)
0106 {
0107     clkdev32k_disable_and_flush_irq();
0108     irqmask = 0;
0109     regmap_write(regmap_st, AT91_ST_IER, irqmask);
0110     return 0;
0111 }
0112 
0113 static int clkevt32k_set_oneshot(struct clock_event_device *dev)
0114 {
0115     clkdev32k_disable_and_flush_irq();
0116 
0117     /*
0118      * ALM for oneshot irqs, set by next_event()
0119      * before 32 seconds have passed.
0120      */
0121     irqmask = AT91_ST_ALMS;
0122     regmap_write(regmap_st, AT91_ST_RTAR, last_crtr);
0123     regmap_write(regmap_st, AT91_ST_IER, irqmask);
0124     return 0;
0125 }
0126 
0127 static int clkevt32k_set_periodic(struct clock_event_device *dev)
0128 {
0129     clkdev32k_disable_and_flush_irq();
0130 
0131     /* PIT for periodic irqs; fixed rate of 1/HZ */
0132     irqmask = AT91_ST_PITS;
0133     regmap_write(regmap_st, AT91_ST_PIMR, timer_latch);
0134     regmap_write(regmap_st, AT91_ST_IER, irqmask);
0135     return 0;
0136 }
0137 
0138 static int
0139 clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
0140 {
0141     u32     alm;
0142     unsigned int    val;
0143 
0144     BUG_ON(delta < 2);
0145 
0146     /* The alarm IRQ uses absolute time (now+delta), not the relative
0147      * time (delta) in our calling convention.  Like all clockevents
0148      * using such "match" hardware, we have a race to defend against.
0149      *
0150      * Our defense here is to have set up the clockevent device so the
0151      * delta is at least two.  That way we never end up writing RTAR
0152      * with the value then held in CRTR ... which would mean the match
0153      * wouldn't trigger until 32 seconds later, after CRTR wraps.
0154      */
0155     alm = read_CRTR();
0156 
0157     /* Cancel any pending alarm; flush any pending IRQ */
0158     regmap_write(regmap_st, AT91_ST_RTAR, alm);
0159     regmap_read(regmap_st, AT91_ST_SR, &val);
0160 
0161     /* Schedule alarm by writing RTAR. */
0162     alm += delta;
0163     regmap_write(regmap_st, AT91_ST_RTAR, alm);
0164 
0165     return 0;
0166 }
0167 
0168 static struct clock_event_device clkevt = {
0169     .name           = "at91_tick",
0170     .features       = CLOCK_EVT_FEAT_PERIODIC |
0171                   CLOCK_EVT_FEAT_ONESHOT,
0172     .rating         = 150,
0173     .set_next_event     = clkevt32k_next_event,
0174     .set_state_shutdown = clkevt32k_shutdown,
0175     .set_state_periodic = clkevt32k_set_periodic,
0176     .set_state_oneshot  = clkevt32k_set_oneshot,
0177     .tick_resume        = clkevt32k_shutdown,
0178 };
0179 
0180 /*
0181  * ST (system timer) module supports both clockevents and clocksource.
0182  */
0183 static int __init atmel_st_timer_init(struct device_node *node)
0184 {
0185     struct clk *sclk;
0186     unsigned int sclk_rate, val;
0187     int irq, ret;
0188 
0189     regmap_st = syscon_node_to_regmap(node);
0190     if (IS_ERR(regmap_st)) {
0191         pr_err("Unable to get regmap\n");
0192         return PTR_ERR(regmap_st);
0193     }
0194 
0195     /* Disable all timer interrupts, and clear any pending ones */
0196     regmap_write(regmap_st, AT91_ST_IDR,
0197         AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
0198     regmap_read(regmap_st, AT91_ST_SR, &val);
0199 
0200     /* Get the interrupts property */
0201     irq  = irq_of_parse_and_map(node, 0);
0202     if (!irq) {
0203         pr_err("Unable to get IRQ from DT\n");
0204         return -EINVAL;
0205     }
0206 
0207     /* Make IRQs happen for the system timer */
0208     ret = request_irq(irq, at91rm9200_timer_interrupt,
0209               IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
0210               "at91_tick", regmap_st);
0211     if (ret) {
0212         pr_err("Unable to setup IRQ\n");
0213         return ret;
0214     }
0215 
0216     sclk = of_clk_get(node, 0);
0217     if (IS_ERR(sclk)) {
0218         pr_err("Unable to get slow clock\n");
0219         return PTR_ERR(sclk);
0220     }
0221 
0222     ret = clk_prepare_enable(sclk);
0223     if (ret) {
0224         pr_err("Could not enable slow clock\n");
0225         return ret;
0226     }
0227 
0228     sclk_rate = clk_get_rate(sclk);
0229     if (!sclk_rate) {
0230         pr_err("Invalid slow clock rate\n");
0231         return -EINVAL;
0232     }
0233     timer_latch = (sclk_rate + HZ / 2) / HZ;
0234 
0235     /* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
0236      * directly for the clocksource and all clockevents, after adjusting
0237      * its prescaler from the 1 Hz default.
0238      */
0239     regmap_write(regmap_st, AT91_ST_RTMR, 1);
0240 
0241     /* Setup timer clockevent, with minimum of two ticks (important!!) */
0242     clkevt.cpumask = cpumask_of(0);
0243     clockevents_config_and_register(&clkevt, sclk_rate,
0244                     2, AT91_ST_ALMV);
0245 
0246     /* register clocksource */
0247     return clocksource_register_hz(&clk32k, sclk_rate);
0248 }
0249 TIMER_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
0250                atmel_st_timer_init);