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 int __init efm32_clocksource_init(struct device_node *np)
 123{
 124        struct clk *clk;
 125        void __iomem *base;
 126        unsigned long rate;
 127        int ret;
 128
 129        clk = of_clk_get(np, 0);
 130        if (IS_ERR(clk)) {
 131                ret = PTR_ERR(clk);
 132                pr_err("failed to get clock for clocksource (%d)\n", ret);
 133                goto err_clk_get;
 134        }
 135
 136        ret = clk_prepare_enable(clk);
 137        if (ret) {
 138                pr_err("failed to enable timer clock for clocksource (%d)\n",
 139                       ret);
 140                goto err_clk_enable;
 141        }
 142        rate = clk_get_rate(clk);
 143
 144        base = of_iomap(np, 0);
 145        if (!base) {
 146                ret = -EADDRNOTAVAIL;
 147                pr_err("failed to map registers for clocksource\n");
 148                goto err_iomap;
 149        }
 150
 151        writel_relaxed(TIMERn_CTRL_PRESC_1024 |
 152                       TIMERn_CTRL_CLKSEL_PRESCHFPERCLK |
 153                       TIMERn_CTRL_MODE_UP, base + TIMERn_CTRL);
 154        writel_relaxed(TIMERn_CMD_START, base + TIMERn_CMD);
 155
 156        ret = clocksource_mmio_init(base + TIMERn_CNT, "efm32 timer",
 157                                    DIV_ROUND_CLOSEST(rate, 1024), 200, 16,
 158                                    clocksource_mmio_readl_up);
 159        if (ret) {
 160                pr_err("failed to init clocksource (%d)\n", ret);
 161                goto err_clocksource_init;
 162        }
 163
 164        return 0;
 165
 166err_clocksource_init:
 167
 168        iounmap(base);
 169err_iomap:
 170
 171        clk_disable_unprepare(clk);
 172err_clk_enable:
 173
 174        clk_put(clk);
 175err_clk_get:
 176
 177        return ret;
 178}
 179
 180static int __init efm32_clockevent_init(struct device_node *np)
 181{
 182        struct clk *clk;
 183        void __iomem *base;
 184        unsigned long rate;
 185        int irq;
 186        int ret;
 187
 188        clk = of_clk_get(np, 0);
 189        if (IS_ERR(clk)) {
 190                ret = PTR_ERR(clk);
 191                pr_err("failed to get clock for clockevent (%d)\n", ret);
 192                goto err_clk_get;
 193        }
 194
 195        ret = clk_prepare_enable(clk);
 196        if (ret) {
 197                pr_err("failed to enable timer clock for clockevent (%d)\n",
 198                       ret);
 199                goto err_clk_enable;
 200        }
 201        rate = clk_get_rate(clk);
 202
 203        base = of_iomap(np, 0);
 204        if (!base) {
 205                ret = -EADDRNOTAVAIL;
 206                pr_err("failed to map registers for clockevent\n");
 207                goto err_iomap;
 208        }
 209
 210        irq = irq_of_parse_and_map(np, 0);
 211        if (!irq) {
 212                ret = -ENOENT;
 213                pr_err("failed to get irq for clockevent\n");
 214                goto err_get_irq;
 215        }
 216
 217        writel_relaxed(TIMERn_IRQ_UF, base + TIMERn_IEN);
 218
 219        clock_event_ddata.base = base;
 220        clock_event_ddata.periodic_top = DIV_ROUND_CLOSEST(rate, 1024 * HZ);
 221
 222        clockevents_config_and_register(&clock_event_ddata.evtdev,
 223                                        DIV_ROUND_CLOSEST(rate, 1024),
 224                                        0xf, 0xffff);
 225
 226        ret = request_irq(irq, efm32_clock_event_handler, IRQF_TIMER,
 227                          "efm32 clockevent", &clock_event_ddata);
 228        if (ret) {
 229                pr_err("Failed setup irq\n");
 230                goto err_setup_irq;
 231        }
 232
 233        return 0;
 234
 235err_setup_irq:
 236err_get_irq:
 237
 238        iounmap(base);
 239err_iomap:
 240
 241        clk_disable_unprepare(clk);
 242err_clk_enable:
 243
 244        clk_put(clk);
 245err_clk_get:
 246
 247        return ret;
 248}
 249
 250/*
 251 * This function asserts that we have exactly one clocksource and one
 252 * clock_event_device in the end.
 253 */
 254static int __init efm32_timer_init(struct device_node *np)
 255{
 256        static int has_clocksource, has_clockevent;
 257        int ret = 0;
 258
 259        if (!has_clocksource) {
 260                ret = efm32_clocksource_init(np);
 261                if (!ret) {
 262                        has_clocksource = 1;
 263                        return 0;
 264                }
 265        }
 266
 267        if (!has_clockevent) {
 268                ret = efm32_clockevent_init(np);
 269                if (!ret) {
 270                        has_clockevent = 1;
 271                        return 0;
 272                }
 273        }
 274
 275        return ret;
 276}
 277TIMER_OF_DECLARE(efm32compat, "efm32,timer", efm32_timer_init);
 278TIMER_OF_DECLARE(efm32, "energymicro,efm32-timer", efm32_timer_init);
 279