Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Clocksource using the Low Power Timer found in the Low Power Controller (LPC)
0004  *
0005  * Copyright (C) 2015 STMicroelectronics – All Rights Reserved
0006  *
0007  * Author(s): Francesco Virlinzi <francesco.virlinzi@st.com>
0008  *        Ajit Pal Singh <ajitpal.singh@st.com>
0009  */
0010 
0011 #include <linux/clk.h>
0012 #include <linux/clocksource.h>
0013 #include <linux/init.h>
0014 #include <linux/of_address.h>
0015 #include <linux/sched_clock.h>
0016 #include <linux/slab.h>
0017 
0018 #include <dt-bindings/mfd/st-lpc.h>
0019 
0020 /* Low Power Timer */
0021 #define LPC_LPT_LSB_OFF     0x400
0022 #define LPC_LPT_MSB_OFF     0x404
0023 #define LPC_LPT_START_OFF   0x408
0024 
0025 static struct st_clksrc_ddata {
0026     struct clk      *clk;
0027     void __iomem        *base;
0028 } ddata;
0029 
0030 static void __init st_clksrc_reset(void)
0031 {
0032     writel_relaxed(0, ddata.base + LPC_LPT_START_OFF);
0033     writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF);
0034     writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF);
0035     writel_relaxed(1, ddata.base + LPC_LPT_START_OFF);
0036 }
0037 
0038 static u64 notrace st_clksrc_sched_clock_read(void)
0039 {
0040     return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF);
0041 }
0042 
0043 static int __init st_clksrc_init(void)
0044 {
0045     unsigned long rate;
0046     int ret;
0047 
0048     st_clksrc_reset();
0049 
0050     rate = clk_get_rate(ddata.clk);
0051 
0052     sched_clock_register(st_clksrc_sched_clock_read, 32, rate);
0053 
0054     ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF,
0055                     "clksrc-st-lpc", rate, 300, 32,
0056                     clocksource_mmio_readl_up);
0057     if (ret) {
0058         pr_err("clksrc-st-lpc: Failed to register clocksource\n");
0059         return ret;
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static int __init st_clksrc_setup_clk(struct device_node *np)
0066 {
0067     struct clk *clk;
0068 
0069     clk = of_clk_get(np, 0);
0070     if (IS_ERR(clk)) {
0071         pr_err("clksrc-st-lpc: Failed to get LPC clock\n");
0072         return PTR_ERR(clk);
0073     }
0074 
0075     if (clk_prepare_enable(clk)) {
0076         pr_err("clksrc-st-lpc: Failed to enable LPC clock\n");
0077         return -EINVAL;
0078     }
0079 
0080     if (!clk_get_rate(clk)) {
0081         pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n");
0082         clk_disable_unprepare(clk);
0083         return -EINVAL;
0084     }
0085 
0086     ddata.clk = clk;
0087 
0088     return 0;
0089 }
0090 
0091 static int __init st_clksrc_of_register(struct device_node *np)
0092 {
0093     int ret;
0094     uint32_t mode;
0095 
0096     ret = of_property_read_u32(np, "st,lpc-mode", &mode);
0097     if (ret) {
0098         pr_err("clksrc-st-lpc: An LPC mode must be provided\n");
0099         return ret;
0100     }
0101 
0102     /* LPC can either run as a Clocksource or in RTC or WDT mode */
0103     if (mode != ST_LPC_MODE_CLKSRC)
0104         return 0;
0105 
0106     ddata.base = of_iomap(np, 0);
0107     if (!ddata.base) {
0108         pr_err("clksrc-st-lpc: Unable to map iomem\n");
0109         return -ENXIO;
0110     }
0111 
0112     ret = st_clksrc_setup_clk(np);
0113     if (ret) {
0114         iounmap(ddata.base);
0115         return ret;
0116     }
0117 
0118     ret = st_clksrc_init();
0119     if (ret) {
0120         clk_disable_unprepare(ddata.clk);
0121         clk_put(ddata.clk);
0122         iounmap(ddata.base);
0123         return ret;
0124     }
0125 
0126     pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n",
0127         clk_get_rate(ddata.clk));
0128 
0129     return ret;
0130 }
0131 TIMER_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register);