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