Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) Maxime Coquelin 2015
0004  * Author:  Maxime Coquelin <mcoquelin.stm32@gmail.com>
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/clocksource.h>
0009 #include <linux/clockchips.h>
0010 #include <linux/io.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/clk.h>
0014 #include <linux/bitops.h>
0015 
0016 #define SYST_CSR    0x00
0017 #define SYST_RVR    0x04
0018 #define SYST_CVR    0x08
0019 #define SYST_CALIB  0x0c
0020 
0021 #define SYST_CSR_ENABLE BIT(0)
0022 
0023 #define SYSTICK_LOAD_RELOAD_MASK 0x00FFFFFF
0024 
0025 static int __init system_timer_of_register(struct device_node *np)
0026 {
0027     struct clk *clk = NULL;
0028     void __iomem *base;
0029     u32 rate;
0030     int ret;
0031 
0032     base = of_iomap(np, 0);
0033     if (!base) {
0034         pr_warn("system-timer: invalid base address\n");
0035         return -ENXIO;
0036     }
0037 
0038     ret = of_property_read_u32(np, "clock-frequency", &rate);
0039     if (ret) {
0040         clk = of_clk_get(np, 0);
0041         if (IS_ERR(clk)) {
0042             ret = PTR_ERR(clk);
0043             goto out_unmap;
0044         }
0045 
0046         ret = clk_prepare_enable(clk);
0047         if (ret)
0048             goto out_clk_put;
0049 
0050         rate = clk_get_rate(clk);
0051         if (!rate) {
0052             ret = -EINVAL;
0053             goto out_clk_disable;
0054         }
0055     }
0056 
0057     writel_relaxed(SYSTICK_LOAD_RELOAD_MASK, base + SYST_RVR);
0058     writel_relaxed(SYST_CSR_ENABLE, base + SYST_CSR);
0059 
0060     ret = clocksource_mmio_init(base + SYST_CVR, "arm_system_timer", rate,
0061             200, 24, clocksource_mmio_readl_down);
0062     if (ret) {
0063         pr_err("failed to init clocksource (%d)\n", ret);
0064         if (clk)
0065             goto out_clk_disable;
0066         else
0067             goto out_unmap;
0068     }
0069 
0070     pr_info("ARM System timer initialized as clocksource\n");
0071 
0072     return 0;
0073 
0074 out_clk_disable:
0075     clk_disable_unprepare(clk);
0076 out_clk_put:
0077     clk_put(clk);
0078 out_unmap:
0079     iounmap(base);
0080     pr_warn("ARM System timer register failed (%d)\n", ret);
0081 
0082     return ret;
0083 }
0084 
0085 TIMER_OF_DECLARE(arm_systick, "arm,armv7m-systick",
0086             system_timer_of_register);