linux/drivers/clocksource/armv7m_systick.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) Maxime Coquelin 2015
   4 * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/clocksource.h>
   9#include <linux/clockchips.h>
  10#include <linux/io.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/clk.h>
  14#include <linux/bitops.h>
  15
  16#define SYST_CSR        0x00
  17#define SYST_RVR        0x04
  18#define SYST_CVR        0x08
  19#define SYST_CALIB      0x0c
  20
  21#define SYST_CSR_ENABLE BIT(0)
  22
  23#define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
  24
  25static int __init system_timer_of_register(struct device_node *np)
  26{
  27        struct clk *clk = NULL;
  28        void __iomem *base;
  29        u32 rate;
  30        int ret;
  31
  32        base = of_iomap(np, 0);
  33        if (!base) {
  34                pr_warn("system-timer: invalid base address\n");
  35                return -ENXIO;
  36        }
  37
  38        ret = of_property_read_u32(np, "clock-frequency", &rate);
  39        if (ret) {
  40                clk = of_clk_get(np, 0);
  41                if (IS_ERR(clk)) {
  42                        ret = PTR_ERR(clk);
  43                        goto out_unmap;
  44                }
  45
  46                ret = clk_prepare_enable(clk);
  47                if (ret)
  48                        goto out_clk_put;
  49
  50                rate = clk_get_rate(clk);
  51                if (!rate) {
  52                        ret = -EINVAL;
  53                        goto out_clk_disable;
  54                }
  55        }
  56
  57        writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
  58        writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
  59
  60        ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
  61                        200, 24, clocksource_mmio_readl_down);
  62        if (ret) {
  63                pr_err("failed to init clocksource (%d)\n", ret);
  64                if (clk)
  65                        goto out_clk_disable;
  66                else
  67                        goto out_unmap;
  68        }
  69
  70        pr_info("ARM System timer initialized as clocksource\n");
  71
  72        return 0;
  73
  74out_clk_disable:
  75        clk_disable_unprepare(clk);
  76out_clk_put:
  77        clk_put(clk);
  78out_unmap:
  79        iounmap(base);
  80        pr_warn("ARM System timer register failed (%d)\n", ret);
  81
  82        return ret;
  83}
  84
  85TIMER_OF_DECLARE(arm_systick, "arm,armv7m-systick",
  86                        system_timer_of_register);
  87