linux/drivers/clocksource/timer-efm32.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2013 Pengutronix
   4 * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
   5 */
   6
   7#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   8
   9#include <linux/kernel.h>
  10#include <linux/clocksource.h>
  11#include <linux/clockchips.h>
  12#include <linux/irq.h>
  13#include <linux/interrupt.h>
  14#include <linux/of.h>
  15#include <linux/of_address.h>
  16#include <linux/of_irq.h>
  17#include <linux/clk.h>
  18
  19#define TIMERn_CTRL                     0x00
  20#define TIMERn_CTRL_PRESC(val)                  (((val) & 0xf) << 24)
  21#define TIMERn_CTRL_PRESC_1024                  TIMERn_CTRL_PRESC(10)
  22#define TIMERn_CTRL_CLKSEL(val)                 (((val) & 0x3) << 16)
  23#define TIMERn_CTRL_CLKSEL_PRESCHFPERCLK        TIMERn_CTRL_CLKSEL(0)
  24#define TIMERn_CTRL_OSMEN                       0x00000010
  25#define TIMERn_CTRL_MODE(val)                   (((val) & 0x3) <<  0)
  26#define TIMERn_CTRL_MODE_UP                     TIMERn_CTRL_MODE(0)
  27#define TIMERn_CTRL_MODE_DOWN                   TIMERn_CTRL_MODE(1)
  28
  29#define TIMERn_CMD                      0x04
  30#define TIMERn_CMD_START                        0x00000001
  31#define TIMERn_CMD_STOP                         0x00000002
  32
  33#define TIMERn_IEN                      0x0c
  34#define TIMERn_IF                       0x10
  35#define TIMERn_IFS                      0x14
  36#define TIMERn_IFC                      0x18
  37#define TIMERn_IRQ_UF                           0x00000002
  38
  39#define TIMERn_TOP                      0x1c
  40#define TIMERn_CNT                      0x24
  41
  42struct efm32_clock_event_ddata {
  43        struct clock_event_device evtdev;
  44        void __iomem *base;
  45        unsigned periodic_top;
  46};
  47
  48static int efm32_clock_event_shutdown(struct clock_event_device *evtdev)
  49{
  50        struct efm32_clock_event_ddata *ddata =
  51                container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
  52
  53        writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
  54        return 0;
  55}
  56
  57static int efm32_clock_event_set_oneshot(struct clock_event_device *evtdev)
  58{
  59        struct efm32_clock_event_ddata *ddata =
  60                container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
  61
  62        writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
  63        writel_relaxed(TIMERn_CTRL_PRESC_1024 |
  64                       TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
  65                       TIMERn_CTRL_OSMEN |
  66                       TIMERn_CTRL_MODE_DOWN,
  67                       ddata->base + TIMERn_CTRL);
  68        return 0;
  69}
  70
  71static int efm32_clock_event_set_periodic(struct clock_event_device *evtdev)
  72{
  73        struct efm32_clock_event_ddata *ddata =
  74                container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
  75
  76        writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
  77        writel_relaxed(ddata->periodic_top, ddata->base + TIMERn_TOP);
  78        writel_relaxed(TIMERn_CTRL_PRESC_1024 |
  79                       TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
  80                       TIMERn_CTRL_MODE_DOWN,
  81                       ddata->base + TIMERn_CTRL);
  82        writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
  83        return 0;
  84}
  85
  86static int efm32_clock_event_set_next_event(unsigned long evt,
  87                                            struct clock_event_device *evtdev)
  88{
  89        struct efm32_clock_event_ddata *ddata =
  90                container_of(evtdev, struct efm32_clock_event_ddata, evtdev);
  91
  92        writel_relaxed(TIMERn_CMD_STOP, ddata->base + TIMERn_CMD);
  93        writel_relaxed(evt, ddata->base + TIMERn_CNT);
  94        writel_relaxed(TIMERn_CMD_START, ddata->base + TIMERn_CMD);
  95
  96        return 0;
  97}
  98
  99static irqreturn_t efm32_clock_event_handler(int irq, void *dev_id)
 100{
 101        struct efm32_clock_event_ddata *ddata = dev_id;
 102
 103        writel_relaxed(TIMERn_IRQ_UF, ddata->base + TIMERn_IFC);
 104
 105        ddata->evtdev.event_handler(&ddata->evtdev);
 106
 107        return IRQ_HANDLED;
 108}
 109
 110static struct efm32_clock_event_ddata clock_event_ddata = {
 111        .evtdev = {
 112                .name = "efm32 clockevent",
 113                .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
 114                .set_state_shutdown = efm32_clock_event_shutdown,
 115                .set_state_periodic = efm32_clock_event_set_periodic,
 116                .set_state_oneshot = efm32_clock_event_set_oneshot,
 117                .set_next_event = efm32_clock_event_set_next_event,
 118                .rating = 200,
 119        },
 120};
 121
 122static struct irqaction efm32_clock_event_irq = {
 123        .name = "efm32 clockevent",
 124        .flags = IRQF_TIMER,
 125        .handler = efm32_clock_event_handler,
 126        .dev_id = &clock_event_ddata,
 127};
 128
 129static int __init efm32_clocksource_init(struct device_node *np)
 130{
 131        struct clk *clk;
 132        void __iomem *base;
 133        unsigned long rate;
 134        int ret;
 135
 136        clk = of_clk_get(np, 0);
 137        if (IS_ERR(clk)) {
 138                ret = PTR_ERR(clk);
 139                pr_err("failed to get clock for clocksource (%d)\n", ret);
 140                goto err_clk_get;
 141        }
 142
 143        ret = clk_prepare_enable(clk);
 144        if (ret) {
 145                pr_err("failed to enable timer clock for clocksource (%d)\n",
 146                       ret);
 147                goto err_clk_enable;
 148        }
 149        rate = clk_get_rate(clk);
 150
 151        base = of_iomap(np, 0);
 152        if (!base) {
 153                ret = -EADDRNOTAVAIL;
 154                pr_err("failed to map registers for clocksource\n");
 155                goto err_iomap;
 156        }
 157
 158        writel_relaxed(TIMERn_CTRL_PRESC_1024 |
 159                       TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
 160                       TIMERn_CTRL_MODE_UP, base + TIMERn_CTRL);
 161        writel_relaxed(TIMERn_CMD_START, base + TIMERn_CMD);
 162
 163        ret = clocksource_mmio_init(base + TIMERn_CNT, "efm32 timer",
 164                                    DIV_ROUND_CLOSEST(rate, 1024), 200, 16,
 165                                    clocksource_mmio_readl_up);
 166        if (ret) {
 167                pr_err("failed to init clocksource (%d)\n", ret);
 168                goto err_clocksource_init;
 169        }
 170
 171        return 0;
 172
 173err_clocksource_init:
 174
 175        iounmap(base);
 176err_iomap:
 177
 178        clk_disable_unprepare(clk);
 179err_clk_enable:
 180
 181        clk_put(clk);
 182err_clk_get:
 183
 184        return ret;
 185}
 186
 187static int __init efm32_clockevent_init(struct device_node *np)
 188{
 189        struct clk *clk;
 190        void __iomem *base;
 191        unsigned long rate;
 192        int irq;
 193        int ret;
 194
 195        clk = of_clk_get(np, 0);
 196        if (IS_ERR(clk)) {
 197                ret = PTR_ERR(clk);
 198                pr_err("failed to get clock for clockevent (%d)\n", ret);
 199                goto err_clk_get;
 200        }
 201
 202        ret = clk_prepare_enable(clk);
 203        if (ret) {
 204                pr_err("failed to enable timer clock for clockevent (%d)\n",
 205                       ret);
 206                goto err_clk_enable;
 207        }
 208        rate = clk_get_rate(clk);
 209
 210        base = of_iomap(np, 0);
 211        if (!base) {
 212                ret = -EADDRNOTAVAIL;
 213                pr_err("failed to map registers for clockevent\n");
 214                goto err_iomap;
 215        }
 216
 217        irq = irq_of_parse_and_map(np, 0);
 218        if (!irq) {
 219                ret = -ENOENT;
 220                pr_err("failed to get irq for clockevent\n");
 221                goto err_get_irq;
 222        }
 223
 224        writel_relaxed(TIMERn_IRQ_UF, base + TIMERn_IEN);
 225
 226        clock_event_ddata.base = base;
 227        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 228
 229        clockevents_config_and_register(&clock_event_ddata.evtdev,
 230                                        DIV_ROUND_CLOSEST(rate, 1024),
 231                                        0xf, 0xffff);
 232
 233        ret = setup_irq(irq, &efm32_clock_event_irq);
 234        if (ret) {
 235                pr_err("Failed setup irq\n");
 236                goto err_setup_irq;
 237        }
 238
 239        return 0;
 240
 241err_setup_irq:
 242err_get_irq:
 243
 244        iounmap(base);
 245err_iomap:
 246
 247        clk_disable_unprepare(clk);
 248err_clk_enable:
 249
 250        clk_put(clk);
 251err_clk_get:
 252
 253        return ret;
 254}
 255
 256/*
 257 * This function asserts that we have exactly one clocksource and one
 258 * clock_event_device in the end.
 259 */
 260static int __init efm32_timer_init(struct device_node *np)
 261{
 262        static int has_clocksource, has_clockevent;
 263        int ret = 0;
 264
 265        if (!has_clocksource) {
 266                ret = efm32_clocksource_init(np);
 267                if (!ret) {
 268                        has_clocksource = 1;
 269                        return 0;
 270                }
 271        }
 272
 273        if (!has_clockevent) {
 274                ret = efm32_clockevent_init(np);
 275                if (!ret) {
 276                        has_clockevent = 1;
 277                        return 0;
 278                }
 279        }
 280
 281        return ret;
 282}
 283TIMER_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
 284TIMER_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);
 285